Android自定義View實現(xiàn)縱向跑馬燈效果詳解
首先看看效果圖(錄制的gif有點卡,真實的效果還是很流暢的)

實現(xiàn)思路
通過上面的gif圖可以得出結(jié)論,其實它就是同時繪制兩條文本信息,然后通過動畫不斷的改變兩條文本信息距離頂部的高度,以此來實現(xiàn)滾動的效果。
具體實現(xiàn)
首先定義一些要用到的屬性
<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"/> 單個動畫的執(zhí)行時間 </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));
}
}
數(shù)據(jù)為空時調(diào)用父類的方法,設置數(shù)據(jù)以后根據(jù)不同的布局計算寬高。
設置數(shù)據(jù)
public void setTextArray(String[] textArray) {
if(textArray == null || textArray.length <= 1) return;
mTextArray = textArray;
initTextRect();
setTextCurrentOrNextStatus(0, 1, true);
startAnimation();}
initTextRect()方法是計算出單個文本的高度和數(shù)組中最大文本的寬度,文本的高度用來計算繪制文本時的位置,文本的最大寬度在onMeasure()方法的時候會用到。
setTextCurrentOrNextStatus()方法設置當前的position,文本以及下一個position,文本。還有文本距離頂部的初始化高度。
startAnimation() 方法 開始執(zhí)行動畫。
動畫實現(xiàn)
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() 方法得到動畫執(zhí)行的進度,計算出text距離頂部的距離,調(diào)用postInvalidate()方法刷新界面。
onAnimationRepeat() 方法,通過handler延遲reRepeatDelayTime時間,再重新執(zhí)行動畫。
繪制
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);
}
}
總結(jié)
到這里所有的代碼已經(jīng)分析完畢,其實實現(xiàn)這個效果還有很多種方法,通過繼承ViewGroup等等都可以實現(xiàn),大家有興趣可以自己嘗試。希望本文的內(nèi)容對大家的學習或者工作能有所幫助,如果有疑問大家可以留言交流。
- Android TextView實現(xiàn)跑馬燈效果的方法
- Android 中TextView中跑馬燈效果的實現(xiàn)方法
- Android自定義View實現(xiàn)豎直跑馬燈效果案例解析
- Android中使用TextView實現(xiàn)文字跑馬燈效果
- Android跑馬燈MarqueeView源碼解析
- Android基于TextView不獲取焦點實現(xiàn)跑馬燈效果
- Android自定義textview實現(xiàn)豎直滾動跑馬燈效果
- Android 實現(xiàn)不依賴焦點和選中的TextView跑馬燈
- Android基于TextView屬性android:ellipsize實現(xiàn)跑馬燈效果的方法
- android自定義View實現(xiàn)跑馬燈效果
相關文章
android中用xml文件實現(xiàn)帶邊框背景效果的方法
這篇文章主要給大家介紹了在android中xml文件實現(xiàn)帶邊框背景效果的方法,其實實現(xiàn)的功能不是很難,僅作記錄,幫助需要的朋友們做個參考,需要的朋友們下面來一起看看吧。2017-06-06
Android編程實現(xiàn)保存圖片到系統(tǒng)圖庫的方法示例
這篇文章主要介紹了Android編程實現(xiàn)保存圖片到系統(tǒng)圖庫的方法,結(jié)合實例形式分析了Android保存圖片到系統(tǒng)圖庫的常見操作方法、注意事項與相關問題解決技巧,需要的朋友可以參考下2017-08-08
Android實戰(zhàn)教程第四十篇之Chronometer實現(xiàn)倒計時
這篇文章主要介紹了Android實戰(zhàn)教程第四十篇之Chronometer實現(xiàn)倒計時,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11
ViewPager 與 Fragment相結(jié)合實現(xiàn)微信界面實例代碼
這篇文章主要介紹了ViewPager 與 Fragment相結(jié)合實現(xiàn)微信界面實例代碼的相關資料,需要的朋友可以參考下2016-07-07
android實現(xiàn)漢字轉(zhuǎn)拼音功能 帶多音字識別
這篇文章主要介紹了android實現(xiàn)漢字轉(zhuǎn)拼音功能,帶多音字識別,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02

