首先看看效果圖(錄製的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等等都可以實現,大家有興趣可以自己嘗試。希望本文的內容對大家的學習或者工作能有所協助,如果有疑問大家可以留言交流。