自定義View實現文本水平方向的跑馬燈效果,可以設置文本相關屬性及滾動速度,以及滾動方式
/**
* Created by wyl on 2018/10/10.
*/
public class MarqueeView extends View {
private static final String TAG = " MarqueeView ";
private final float DEF_SIZE = 250.0f;//默認字體大小
private final int DEF_COLOR = 0xff0000;
private float mSpeed = 4.0F; //默認滾動速度
private boolean isScroll = true; //是否自動滾動
private Context mContext;
private Paint mPaint; //文字畫筆
private String mText;//展示內容
private float mCoordinateX;//文字起始位置的X軸偏移量
private float mCoordinateX_;//首尾緊跟滾動 新一輪文字起始位置的X軸偏移量
private float mCoordinateY;//Y軸偏移量
private float mTextWidth; //文本的寬度
private int mViewWidth; //控件的寬度
private int mViewHeight;//控件高度
public static int SCROLL_ENDED = 1, SCROLL_FOLLOW = 2;
private int mScrollType;//文本滾動方式 緊鄰滾動、一行結束之後滾動
private int mFollowSpace = 10;//相鄰滾動 首尾文字間距
public MarqueeView(Context context) {
super(context);
init(context);
}
public MarqueeView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MarqueeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
this.mContext = context;
if (TextUtils.isEmpty(mText)) {
mText = "歡迎光臨";
}
mPaint = new Paint();
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
mPaint.setAntiAlias(true);
mPaint.setTextSize(DEF_SIZE);
mPaint.setColor(DEF_COLOR);
}
public void setText(String text) {
mText = text;
if (TextUtils.isEmpty(mText)) {
mText = "歡迎光臨!";
}
requestLayout();//設置字體過後 需要重新測量View
invalidate();//重新繪製
}
public void setTextSize(float textSize) {
mPaint.setTextSize(textSize <= 0 ? DEF_SIZE : textSize);
requestLayout();
invalidate();
}
public void setTextColor(int textColor) {
mPaint.setColor(textColor);
invalidate();
}
//設置滾動速度
public void setTextSpeed(float speed) {
this.mSpeed = speed < 1 ? 1 : speed;
invalidate();
}
/**
* //設置滾動相鄰距離
* //根據控件寬度設置最好
*
* @param space
*/
public void setFollowSpace(int space) {
this.mFollowSpace = space < 10 ? 10 : space;
invalidate();
}
//設置滾動方式
public void setScrollType(int type) {
mScrollType = type;
invalidate();
}
//設置滾動
public void setScroll(boolean isScroll) {
this.isScroll = isScroll;
invalidate();
}
//是否滾動
public boolean isScroll() {
return isScroll;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCoordinateX = getWidth();
mCoordinateX_ = mCoordinateX;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mTextWidth = mPaint.measureText(mText);//測量文本長度
//從屏幕最右端開始
// mCoordinateX = getResources().getDisplayMetrics().widthPixels;
//測量控件寬度
mViewWidth = measureW(widthMeasureSpec);
//測量控件高度
mViewHeight = measureH(heightMeasureSpec);
//測量文本起始位置Y軸的偏移量 使其水平居中
Paint.FontMetricsInt fm = mPaint.getFontMetricsInt();
mCoordinateY = getHeight() / 2 - fm.descent + (fm.descent - fm.ascent) / 2;
//根據文本顯示內容選擇
//----------------------top
//----------------------ascent
// 內容(中文/英文)
//----------------------baseline
//----------------------descent
//----------------------bottom
//mCoordinateY = getHeight() / 2 - fm.descent + (fm.bottom- fm.top) / 2
mCoordinateX = mViewWidth;
mCoordinateX_ = mCoordinateX;
setMeasuredDimension(mViewWidth, mViewHeight);
}
private int measureW(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {//match_parent 或者 具體的值
result = specSize;
} else {//wrap_content 由文本長度 及左右padding決定
result = (int) mPaint.measureText(mText) + getPaddingLeft()
+ getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
private int measureH(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {//match_parent 或者 具體的值
result = specSize;
} else {//wrap_content 控件高度由字體大小 及 上下padding決定
result = (int) mPaint.getTextSize() + getPaddingTop()
+ getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if ((Math.abs(mCoordinateX) > mTextWidth && mCoordinateX < 0)) {
mCoordinateX = mCoordinateX_;
mCoordinateX_ = getWidth();
}
Paint.FontMetricsInt fm = mPaint.getFontMetricsInt();
mCoordinateY = getHeight() / 2 - fm.descent + (fm.descent - fm.ascent) / 2;
//繪製文本
canvas.drawText(mText, mCoordinateX, mCoordinateY, mPaint);
//如果不能滾動 則停止繪製
if (!isScroll) {
return;
}
//每繪製一次 X軸的偏移量 減去滾動速度 再進行繪製
mCoordinateX -= mSpeed;
if (mScrollType == SCROLL_ENDED) {
//當文本向左偏移text的寬度後 即所有文字都從屏幕左側出去後 重置X軸的偏移量 讓文字重新由右邊進入
if (Math.abs(mCoordinateX) > mTextWidth && mCoordinateX < 0) {
mCoordinateX = mViewWidth;//重置X軸偏移量爲控件寬度
}
} else {
//當文本剩餘內容快要結束(快要離開屏幕mFollowSpace距離)時,開始繪製新一輪的文字
if ((Math.abs(mCoordinateX) + mFollowSpace) > mTextWidth && mCoordinateX < 0 && mCoordinateX_ > -4) {
canvas.drawText(mText, mCoordinateX_, mCoordinateY, mPaint);
mCoordinateX_ -= mSpeed;
}
}
invalidate();
}
}