Android 自定义View实现文本水平方向的跑马灯效果

xiaoxiao2021-02-28  9

自定义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(); } }
转载请注明原文地址: https://www.6miu.com/read-2150135.html

最新回复(0)