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

自定义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();

    }
}

猜你喜欢

转载自blog.csdn.net/wyl_tyrael/article/details/78356428