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();

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章