安卓自动横向滚动的文本视图

71
我正在尝试实现一个单行文本视图,使其能够自动滚动。但是我不幸无法让它正常工作。AutoScrollTextView声明在LinearLayout(宽度和高度=fill_parent)内部。该类基本上使用Handler调用自身以按给定量滚动。我已经简化了代码,只显示每秒应滚动5个像素的文本视图。
日志输出是正确的,getScrollX()方法返回适当的scrollX位置。
如果我不调用requestLayout(),则什么也不会绘制。invalidate()没有效果。
有人有线索吗?
public class AutoScrollTextView extends TextView {

    public AutoScrollTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setSingleLine();
        setEllipsize(null);
        setText("Single-line text view that scrolls automatically if the text is too long to fit in the widget");
    }

    // begin to scroll the text from the original position
    public void startScrolling() {
        scrollHandler.sendEmptyMessage(0);
    }

    private Handler scrollHandler = new Handler() {
        private static final int REFRESH_INTERVAL = 1000;

        public void handleMessage(Message msg) {
            scrollBy(5, 0);
            requestLayout();
            Log.debug("Scrolled to " + getScrollX() + " px");
            sendEmptyMessageDelayed(0, REFRESH_INTERVAL);
        }
    };
}

通常,要使文本滚动,它应该处于焦点状态。您尝试过将焦点放在布局上吗?或者使用setSelected()方法来设置视图的选中状态? - sat
是的,我尝试从活动中和自定义小部件内部的处理程序执行此操作。 - Vincent Mimoun-Prat
9个回答

246
如果您不需要对TextView进行子类化,您可以在布局文件中尝试以下操作:
    <TextView
        android:text="Single-line text view that scrolls automatically if the text is too long to fit in the widget" 
        android:singleLine="true"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit ="marquee_forever"
        android:focusable="true"
        android:focusableInTouchMode="true" 
        android:scrollHorizontally="true"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"/>

另外,在您的代码中使用以下内容:

findViewById(R.id.serviceColorCode).setSelected(true);

[基于评论编辑的回答]


23
当走马灯完成一次循环后,有没有可能让它返回(反向运行)? - pleerock
4
能否增加滚动速度? - Bharath
27
TextView必须被设置为已选中状态:textView.setSelected(true); - alfo888_ibg
6
请注意,应该使用 maxLines="1",因为 singleLine 已被弃用。 - Neon Warge
4
为了使其工作,你必须使用singleLine属性。只尝试了在AppCompatTextView上使用maxLines,但是不起作用。因此,singleLine和setSelected(..)是关键。 - bengous
显示剩余14条评论

25

在@rajat的回答中,这些XML代码如下:

<TextView
        android:text="Single-line text view that scrolls automatically if the text is too long to fit in the widget" 
        android:singleLine="true" 
        android:ellipsize="marquee"
        android:marqueeRepeatLimit ="marquee_forever"
        android:focusable="true"
        android:focusableInTouchMode="true" 
        android:scrollHorizontally="true"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"/>
我们需要设置。
TextView tv=(TextView)findViewById(R.id.textview1);
  tv.setSelected(true); 

最终使我的工作成果


在滚动时应该看到整个文本。最终的文本是带点的(太......)。因此没有滚动的意义。请建议解决方案。 - Sagar Nayak
我认为你可能设置了android:ellipsize="end"。检查一下。如果不是这种情况,请告诉我。另外,如果可能的话,请在这里分享你的代码。 - Sujeet Kumar Mehta
不好意思我打错了,应该是“跑马灯”的意思。但我正在一个RecyclerView中使用它。外层的RecyclerView包含一个元素,里面有一个TextView。然后这个TextView有一段长文本,我想要把它显示在一行上,并且自动无限滚动。 - Sagar Nayak
1
不确定为什么在使用RecyclerView时会禁用自动滚动。 - Sujeet Kumar Mehta

18

我的解决方案有效:

<TextView
     android:id="@+id/titolotxt"
     android:layout_width="..."
     android:layout_height="..."
     android:ellipsize="marquee"
     android:gravity="left"
     android:marqueeRepeatLimit="marquee_forever"
     android:singleLine="true"
     android:text="@string/titolo"/>

而且TextView必须通过代码设置为选定状态:textView.setSelected(true);,例如在onCreate中。


4

提示:如果文本长度不足以超过屏幕大小,则这个功能不能用于短文本。

<  TextView
        android:id="@+id/support"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text=" enter the large text that wont fit on screen "
        android:singleLine="true"
        android:scrollHorizontally="true"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit="marquee_forever"
        />

在您的活动中

 TextView textView=findViewById(R.id.support);
        textView.setSelected(true);

3

为了移动文本,除了添加属性外:

android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"

View必须处于焦点状态,这可以通过两种方式实现:

  1. Programmatically:

    tv.setSelected (true);
    
  2. Do everything in XML by adding requestFocus tag:

    <TextView 
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:ellipsize="marquee"
         android:singleLine="true"
         android:marqueeRepeatLimit="marquee_forever"
         android:focusable="true"
         android:clickable="true"
         android:focusableInTouchMode="true"
         android:scrollHorizontally="true">
         <requestFocus />
    </TextView>
    

谢谢。我想知道为什么其他答案中的所有解决方案都对我无效。 因为缺少指令 android:clickable="true" - ka3ak

3
// this TextView will marquee because it is selected
TextView marqueeText1 = (TextView) findViewById(R.id.marquee_text_1);
marqueeText1.setSelected(true);

<TextView
    android:id="@+id/marquee_text_1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
    android:textSize="24sp"
    android:singleLine="true"
    android:ellipsize="marquee"
    android:marqueeRepeatLimit="marquee_forever"
    android:scrollHorizontally="true" />

1

对于我的情况,唯一有效的方法是使用scrollview并通过编程设置滚动。

片段中的文本视图

<HorizontalScrollView
        android:id="@+id/hsv_fragment_drafting_now_header_info"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="8dp"
        android:scrollbars="none">

        <TextView
               android:id="@+id/tv_fragment_drafting_now_header_info"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:fontFamily="@font/circular_std_book"
               android:maxLines="1"
               android:text="A very long text that will be reaching out the screen or view container"
               android:textSize="16sp" />

</HorizontalScrollView>

动画, sliding_text.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
      android:duration="8000"
      android:fromXDelta="100%"
      android:interpolator="@android:anim/linear_interpolator"
      android:repeatCount="infinite"
      android:repeatMode="restart"
      android:toXDelta="-100%" />

阻止手动滚动并开始动画

headerInfoScroll.setOnTouchListener(object : View.OnTouchListener{
    override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
         return true
    }
})

headerInfo.startAnimation(AnimationUtils.loadAnimation(this.context, R.anim.sliding_text))

0
有时候invalidate无法正常工作,除非你在主线程中调用invalidate,如下所示:
handler.post(new Runnable() {

        @Override
        public void run() {
            yourView.invalidate();
        }
    });

0

setMovementMethod(new ScrollingMovementMethod())setHorizontallyScrolling(true)在我的情况下起作用。

在.java文件中:

tv = findViewById(R.id.textViewID);
tv.setMovementMethod(new ScrollingMovementMethod());
tv.setHorizontallyScrolling(true);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接