Android如何实现跑马灯文本移出屏幕后立即重新滚动
解决Android Marquee文本滚动后延迟重新出现的问题
这个延迟问题其实是Android原生TextView的Marquee动画默认带有重复等待间隔导致的。要实现文本一移出屏幕就立刻重新滚动,我们可以通过两种方式解决:自定义TextView修改原生Marquee的行为,或者完全用自定义动画来实现。
方案一:自定义TextView移除Marquee的等待延迟
原生Marquee在每次滚动结束后会有一段默认的等待时间(大概2秒左右),我们可以通过重写TextView的相关方法来去掉这个延迟:
public class NoDelayMarqueeTextView extends androidx.appcompat.widget.AppCompatTextView { public NoDelayMarqueeTextView(Context context) { super(context); init(); } public NoDelayMarqueeTextView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public NoDelayMarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 开启跑马灯必备属性 setEllipsize(TextUtils.TruncateAt.MARQUEE); setMarqueeRepeatLimit(-1); // 无限重复 setSingleLine(true); setFocusable(true); setFocusableInTouchMode(true); } @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { // 强制保持跑马灯状态,不需要依赖焦点 if (focused) { super.onFocusChanged(focused, direction, previouslyFocusedRect); } } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { // 同样强制保持跑马灯,不依赖窗口焦点 if (hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 每次绘制完成后,立即重新启动Marquee,跳过等待延迟 if (isMarqueeEnabled() && !isFocused()) { startMarquee(); } } @Override public boolean isFocused() { // 欺骗系统,让TextView始终处于"聚焦"状态,保持Marquee运行 return true; } }
使用的时候,在布局里直接替换原来的TextView:
<com.yourpackage.NoDelayMarqueeTextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="你的超长滚动文本内容,不需要额外加空格也能滚动" android:textSize="16sp" />
这个方案的核心是让TextView始终保持聚焦状态,并且在每次绘制后立即重启Marquee,跳过默认的等待间隔。
方案二:用自定义TranslateAnimation实现无延迟滚动
如果原生Marquee的限制太多,我们可以直接用动画来控制文本的滚动,完全自定义速度和循环逻辑:
步骤1:布局文件
<RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clipChildren="true" android:clipToPadding="true"> <TextView android:id="@+id/marqueeText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="你的滚动文本内容" android:textSize="16sp" android:singleLine="true" /> </RelativeLayout>
步骤2:代码中设置动画
TextView marqueeText = findViewById(R.id.marqueeText); marqueeText.measure(0, 0); final int textWidth = marqueeText.getMeasuredWidth(); final int screenWidth = getResources().getDisplayMetrics().widthPixels; // 如果文本长度小于屏幕宽度,复制文本拼接成超长文本(避免滚动留白) if (textWidth < screenWidth) { StringBuilder sb = new StringBuilder(); while (sb.length() * textWidth < screenWidth * 2) { sb.append(marqueeText.getText()).append(" "); } marqueeText.setText(sb.toString()); marqueeText.measure(0, 0); } // 创建平移动画 TranslateAnimation animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, -1f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f); animation.setDuration(10000); // 滚动一次的时间,单位毫秒,可根据需求调整 animation.setRepeatCount(Animation.INFINITE); // 无限重复 animation.setRepeatMode(Animation.RESTART); animation.setInterpolator(new LinearInterpolator()); // 匀速滚动 marqueeText.startAnimation(animation);
这个方案的优势是完全可控,你可以调整滚动速度、重复模式,而且没有原生Marquee的等待延迟,文本一移出屏幕就会立刻从右侧重新出现。
注意事项
- 方案一中的自定义TextView不需要额外添加空格,只要文本长度超过TextView的宽度就会滚动;
- 方案二中如果文本过短,我们通过拼接文本的方式让滚动内容足够长,避免出现留白;
- 如果需要暂停/继续滚动,方案二可以通过
startAnimation()和clearAnimation()来控制,更灵活。
内容的提问来源于stack exchange,提问作者ajay srivas
相关产品推荐
相关产品推荐

