Android自訂View實現縱向跑馬燈效果詳解_Android

來源:互聯網
上載者:User

首先看看效果圖(錄製的gif有點卡,真實的效果還是很流暢的)

實現思路

通過上面的gif圖可以得出結論,其實它就是同時繪製兩條文本資訊,然後通過動畫不斷的改變兩條文本資訊距離頂部的高度,以此來實現滾動的效果。

具體實現

首先定義一些要用到的屬性

<declare-styleable name="MarqueeViewStyle">  <attr name="textSize" format="dimension" />  <attr name="textColor" format="color" />  <attr name="paddingLeft" format="dimension" />  <attr name="paddingTop" format="dimension" />  <attr name="paddingBottom" format="dimension" />  <attr name="paddingTopBottom" format="dimension"/>  <attr name="startDelayTime" format="integer"/> 動畫開始延遲時間<attr name="reRepeatDelayTime" format="integer"/> 動畫重複延遲時間 <attr name="itemAnimationTime" format="integer"/> 單個動畫的執行時間</declare-styleable>

接下來解析屬性值

private void init(Context context, AttributeSet attrs) {   TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MarqueeViewStyle);   mTextColor = typedArray.getColor(R.styleable.MarqueeViewStyle_textColor, Color.BLACK);   mTextSize = typedArray.getDimensionPixelSize(R.styleable.MarqueeViewStyle_textSize, 45);   mPaddingLeft = typedArray.getDimensionPixelSize(R.styleable.MarqueeViewStyle_paddingLeft, 15);   mPaddingTop = mPaddingBottom = typedArray.getDimensionPixelSize(R.styleable.MarqueeViewStyle_paddingTopBottom, 25);   mPaddingTop = typedArray.getDimensionPixelSize(R.styleable.MarqueeViewStyle_paddingTop, mPaddingTop);   mPaddingBottom = typedArray.getDimensionPixelSize(R.styleable.MarqueeViewStyle_paddingBottom, mPaddingBottom);   itemAnimationTime = typedArray.getInteger(R.styleable.MarqueeViewStyle_itemAnimationTime, 1000);   reRepeatDelayTime = typedArray.getInteger(R.styleable.MarqueeViewStyle_reRepeatDelayTime, 1000);   startDelayTime = typedArray.getInteger(R.styleable.MarqueeViewStyle_startDelayTime, 500);   typedArray.recycle();    mPaint = new Paint();    mPaint.setAntiAlias(true);    mPaint.setTextSize(mTextSize);    mPaint.setColor(mTextColor);    mPaint.setTextAlign(Paint.Align.LEFT);}

重寫onMeasure方法

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    if(mTextArray == null || mTextArray.length == 0) {       super.onMeasure(widthMeasureSpec, heightMeasureSpec);    } else {        int width = MeasureSpec.getSize(widthMeasureSpec);      int height = MeasureSpec.getSize(heightMeasureSpec);       ViewGroup.LayoutParams lp = getLayoutParams();        setMeasuredDimension(getViewWidth(lp, width), getViewHeight(lp, height));    }}

資料為空白時調用父類的方法,設定資料以後根據不同的布局計算寬高。

設定資料

public void setTextArray(String[] textArray) {    if(textArray == null || textArray.length <= 1) return;    mTextArray = textArray;    initTextRect();    setTextCurrentOrNextStatus(0, 1, true);    startAnimation();}

initTextRect()方法是計算出單個文本的高度和數組中最大文本的寬度,文本的高度用來計算繪製文本時的位置,文本的最大寬度在onMeasure()方法的時候會用到。

setTextCurrentOrNextStatus()方法設定當前的position,文本以及下一個position,文本。還有文本距離頂部的初始化高度。

startAnimation() 方法 開始執行動畫。

動畫實現

private void startAnimation() {   va = ValueAnimator.ofFloat(0, 1);   va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {     @Override     public void onAnimationUpdate(ValueAnimator animation) {     mProgress = (float) animation.getAnimatedValue();      .   int moveOffset = (int) (mTextMoveOffset * mProgress);    mCurrentTextMoveMarginTop = mCurrentTextInitMarginTop - moveOffset;         mNextTextMoveMarginTop = mNextTextInitMarginTop - moveOffset;         postInvalidate();     }   });   va.addListener(new AnimatorListenerAdapter() {       @Override       public void onAnimationRepeat(Animator animation) {       va.pause();            setTextCurrentOrNextStatus(mNextTextPosition, mNextTextPosition + 1, false);          handler.postDelayed(new Runnable() {             @Override             public void run() {                va.resume();             }     }, reRepeatDelayTime);       }   });   va.setRepeatCount(-1);   va.setDuration(itemAnimationTime);   va.setStartDelay(startDelayTime);   va.start();}

va.setRepeatCount(-1); 設定動畫無限重複

onAnimationUpdate() 方法得到動畫執行的進度,計算出text距離頂部的距離,調用postInvalidate()方法重新整理介面。

onAnimationRepeat() 方法,通過handler延遲reRepeatDelayTime時間,再重新執行動畫。

繪製

protected void onDraw(Canvas canvas) {   if(mTextArray == null || mTextArray.length == 0) {     super.onDraw(canvas);   } else {      canvas.drawText(mCurrentText, mPaddingLeft, mCurrentTextMoveMarginTop, mPaint);    canvas.drawText(mNextText, mPaddingLeft, mNextTextMoveMarginTop, mPaint);   }}

總結

到這裡所有的代碼已經分析完畢,其實實現這個效果還有很多種方法,通過繼承ViewGroup等等都可以實現,大家有興趣可以自己嘗試。希望本文的內容對大家的學習或者工作能有所協助,如果有疑問大家可以留言交流。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.