TextView跑馬燈-兩種實現方式
阿新 • • 發佈:2018-12-17
Android中TextView跑馬燈有多種實現方式;
一種是自定義控制元件,另外一種是寫一個工具類
自定義控制元件
/**
* Created by iblade.Wang on 2018/10/24 10:29
*/
public class MarqueeTextView extends TextView {
public MarqueeTextView(Context context) {
this(context, null);
}
public MarqueeTextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MarqueeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
//預設迴圈一次
setRepeatCount(1);
}
/**
* 強制獲取焦點
*
* @return
*/
@Override
public boolean isFocused() {
return true;
}
/**
* 用於EditText搶注焦點的問題
*/
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (focused) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
}
/**
* Window與Window間焦點發生改變時的回撥
* 解決Dialog搶了焦點後跑馬燈停止
*/
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
if (hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
}
}
/**
* 設定跑馬燈迴圈次數,其中-1表示無限迴圈
*
* @param limit
*/
public void setRepeatCount(int limit) {
//設定單行
setSingleLine();
//設定Ellipsize
setEllipsize(TextUtils.TruncateAt.MARQUEE);
//獲取焦點
setFocusable(true);
//走馬燈的重複次數,-1表示無限迴圈
setMarqueeRepeatLimit(limit);
//強制獲得焦點
setFocusableInTouchMode(true);
}
}
工具類
/**
* Created by iblade.Wang on 2018/10/25 14:41
*/
public class TextViewUtils {
/**
* set TextView Ellipsize marquee
*
* @param textView
*/
public static void marqueeView2(final TextView textView) {
//mRndDuration用於控制速度
final int mRndDuration = 200;
textView.setSingleLine();
textView.setEllipsize(null);
//只有當textView完成繪製後才能計算滾動距離
if (0 != textView.getWidth()) {
scrollText2(textView, mRndDuration);
} else {
textView.getViewTreeObserver()
.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (0 != textView.getWidth()) {
textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
scrollText2(textView, mRndDuration);
}
}
});
}
}
private static void scrollText2(final TextView textView, int mRndDuration) {
Scroller slr = new Scroller(textView.getContext(), new LinearInterpolator());
textView.setScroller(slr);
//字型長度
int scrollingLen = (int) (textView.getPaint().measureText(textView.getText().toString()) + 0.5f);
//滾動時長
int duration = textView.getText().length() * mRndDuration;
int viewWidth = textView.getWidth();
int distance = scrollingLen - viewWidth + textView.getLeft() + textView.getCompoundPaddingLeft() + textView.getCompoundPaddingRight();
if (distance <= 0) {
return;
}
slr.startScroll(0, 0, distance, 0, duration);
textView.invalidate();
final class HandlerListener implements HandlerUtils.OnReceiveMessageListener {
@Override
public void handlerMessage(Message msg) {
int width = textView.getLayoutParams().width;
//寬度不是自適應時,會有不左對齊的bug,暫時用這種辦法規避
if (width != ViewGroup.LayoutParams.WRAP_CONTENT) {
textView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
textView.setText(textView.getText());
textView.getLayoutParams().width = width;
}
}
HandlerListener handlerListener = new HandlerListener();
HandlerUtils.HandlerHolder handlerHolder = new HandlerUtils.HandlerHolder(handlerListener);
handlerHolder.sendEmptyMessageDelayed(0x1, duration + 500);
}
//todo ---------------------以下是通過動畫完成,drawableLeft會有問題------------------------------------
/**
* set TextView Ellipsize marquee
*
* @param textView
*/
public static void marqueeView(final TextView textView) {
final int mRndDuration = 200;
textView.setSingleLine();
textView.setEllipsize(null);
//只有當textView完成繪製後才能計算滾動距離
if (0 != textView.getWidth()) {
scrollText(textView, mRndDuration);
} else {
textView.getViewTreeObserver()
.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (0 != textView.getWidth()) {
textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
scrollText(textView, mRndDuration);
}
}
});
}
}
private static void scrollText(final TextView textView, int mRndDuration) {
//字型長度
int scrollingLen = (int) (textView.getPaint().measureText(textView.getText().toString()) + 0.5f);
//滾動時長
int duration = textView.getText().length() * mRndDuration;
int viewWidth = textView.getWidth();
int distance = scrollingLen - viewWidth + textView.getLeft() + textView.getCompoundPaddingLeft() + textView.getCompoundPaddingRight();
if (distance <= 0) {
return;
}
ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "translationX", 0f, -distance);
animator.setDuration(duration);
animator.start();
}
// /**
// * calculate TextView singleLine widthPixels
// *
// * @param textView textView
// * @return widthPixels
// */
// private static int calculateTextViewLen(TextView textView) {
//
// TextPaint tp = textView.getPaint();
// Rect rect = new Rect();
// String strTxt = textView.getText().toString();
// tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
// int scrollingLen = rect.width();
// rect = null;
// return scrollingLen;
// }
//
// private static int calculateTextViewLen2(TextView textView) {
// return (int) (textView.getPaint().measureText(textView.getText().toString()) + 0.5f);
// }
}
其中工具類中用到了Handler弱引用的工具類,《Android中Handler弱引用的工具類》
但是測試中發現弱引用,部分複雜頁面中又被GC 回收的風險,不建議使用,可以替代為如下:
private static void scrollText2(final TextView textView, int mRndDuration) {
Scroller slr = new Scroller(textView.getContext(), new LinearInterpolator());
textView.setScroller(slr);
//字型長度
int scrollingLen = (int) (textView.getPaint().measureText(textView.getText().toString()) + 0.5f);
//滾動時長
int duration = textView.getText().length() * mRndDuration;
int viewWidth = textView.getWidth();
int distance = scrollingLen - viewWidth + textView.getLeft() + textView.getCompoundPaddingLeft() + textView.getCompoundPaddingRight();
//只允許向左滾動
if (distance <= 0) {
return;
}
slr.startScroll(0, 0, distance, 0, duration);
textView.invalidate();
//有記憶體洩露隱患
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
int width = textView.getLayoutParams().width;
//寬度不是自適應時,會有不左對齊的bug,暫時用這種辦法規避
if (width != ViewGroup.LayoutParams.WRAP_CONTENT) {
textView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
textView.setText(textView.getText());
textView.getLayoutParams().width = width;
}
}, duration + 500);