Android TextView实现跑马灯效果性能优化
在生活中经常见到文字滚动显示场景,比如电子屏幕信息提示、KTV电视上显示播放歌曲信息等,俗称跑马灯。那么在Android中如何简单实现呢?
最简单的就是通过文本控件TextView自带的属性实现,如下:
<TextView
android:id="@+id/srcoll_text"
android:layout_gravity="top"
android:layout_marginTop="@dimen/size_dp_10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:textColor="#fff"
android:textSize="30sp"
/>
最重要的就是以下三个属性:
android:singleLine="true" //单行显示
android:ellipsize="marquee" //显示长度不够时滚动显示
android:marqueeRepeatLimit="marquee_forever" //无限循环滚动
但是以上滚动效果只有在TextView获取焦点时才会触发,所以需要通过代码设置TextView焦点。
srcollText.setEllipsize(TextUtils.TruncateAt.MARQUEE);
srcollText.setSingleLine(true);
srcollText.setMarqueeRepeatLimit(-1);
srcollText.setSelected(true); //设置选中
//或者设置获取焦点
/*
srcollText.setFocusable(true);
srcollText.setFocusableInTouchMode(true);
srcollText.requestFocus();
*/
srcollText.setText("滚动文本内容要足够长,超过TextView设置的宽度");
这样就可以实现横向滚动的跑马灯效果,实践中发现这种方式比较消耗CPU性能,单一功能多消耗CPU 5%左右,网上也要好多优化建议:
1.开启硬件加速
<application
android:hardwareAccelerated="true"
... >
...
</application>
2.自定义TextView,延时降低重绘次数
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.TextView;
public class CustomMarqueeTextView extends TextView {
private static final int MARQUEE_DELAY = 100; // 调整此值以降低帧率
public CustomMarqueeTextView(Context context) {
super(context);
}
public CustomMarqueeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomMarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
postInvalidateDelayed(MARQUEE_DELAY); // 延迟重绘
}
}
3.进一步自定义TextView动画
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class CustomMarqueeTextView extends TextView {
private ValueAnimator animator;
private int scrollOffset;
public CustomMarqueeTextView(Context context) {
super(context);
init();
}
public CustomMarqueeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomMarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
animator = ValueAnimator.ofInt(0, getWidth());
animator.setDuration(5000); // 动画时长
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scrollOffset = (int) animation.getAnimatedValue();
scrollTo(scrollOffset, 0);
}
});
animator.start();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (animator != null) {
animator.cancel();
}
}
}
实践发现效果不明显,性能消耗还是偏高。而改成通过平移动画上下翻滚效果,性能消耗低很多。
在 res/anim 目录下创建 slide_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="0%"
android:toYDelta="-150%"
android:duration="3000"
/>
</set>
<TextView
android:id="@+id/scrolling_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是一段会上下翻滚的文字~"
android:textSize="20sp"
android:padding="16dp" />
实现多段文字轮流上下滚动显示
if (runnable == null) {
final Animation slideUp = AnimationUtils.loadAnimation(mContext, R.anim.slide_up);
runnable = new Runnable() {
@Override
public void run() {
myViewBinding.srcollText.startAnimation(slideUp);
// 切换索引
currentScrollIndex = (currentScrollIndex + 1) % parts.length;
myViewBinding.srcollText.setText(parts[currentScrollIndex]);
if (MainApplication.onFullScreen)
handler.postDelayed(this, slideUp.getDuration()/* + slideDown.getDuration()*/);
}
};
// 启动循环任务
handler.postDelayed(runnable, 1000);
}
这种方式实现整体性能消耗降低3%左右。性能优化就是要积少成多,每个小功能细节上节省一点,应用整体上就会流畅很多。