96

我想在 TextView 上使用选取框效果,但只有在 TextView 获得焦点时才会滚动文本。这是一个问题,因为在我的情况下,它不能。

我在用:

  android:ellipsize="marquee"
  android:marqueeRepeatLimit="marquee_forever"

有没有办法让 TextView 总是滚动它的文本?我已经在 Android Market 应用程序中看到了这一点,应用程序名称将在标题栏中滚动,即使它没有获得焦点,但我在 API 文档中找不到这一点。

4

8 回答 8

122

我今天终于遇到了这个问题,因此hierarchyviewer对 Android Market 应用程序感兴趣。

查看应用程序详细信息屏幕上的标题,他们使用普通的旧TextView. 检查它的属性显示它没有聚焦,无法聚焦并且通常非常普通——除了它被标记为selected

一行代码之后,我让它工作了:)

textView.setSelected(true);

鉴于Javadoc 所说的,这是有道理的:

可以选择或不选择视图。请注意,选择与焦点不同。视图通常在像 ListView 或 GridView 这样的 AdapterView 的上下文中选择。

即当您滚动列表视图中的项目时(如在市场应用程序中),只有此时现在选择的文本才会开始滚动。而且由于这个特定TextView的不是可聚焦或可点击的,它永远不会失去它的选择状态。

不幸的是,据我所知,没有办法从布局 XML 中预设选定状态。
但上面的单线对我来说很好用。

于 2010-09-13T13:06:04.057 回答
76

只需将这些参数放在您的 TextView 中。有用 :)

    android:singleLine="true" 
    android:ellipsize="marquee"
    android:marqueeRepeatLimit ="marquee_forever"
    android:scrollHorizontally="true"
    android:focusable="true"
    android:focusableInTouchMode="true" 
于 2010-08-18T09:58:38.937 回答
63

我一直面临这个问题,我想出的最短解决方案是创建一个从 TextView 派生的新类。该类应覆盖三个方法onFocusChangedonWindowFocusChangedisFocused以使 TextView 全部聚焦。

@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
    if(focused)
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
}

@Override
public void onWindowFocusChanged(boolean focused) {
    if(focused)
        super.onWindowFocusChanged(focused);
}


@Override
public boolean isFocused() {
    return true;
}
于 2010-03-24T01:45:48.823 回答
13

TranslateAnimation通过向一个方向“拉”视图指定的量来工作。您可以设置此“拉动”的开始位置和结束位置。

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta 设置移动起始位置在 X 轴上的偏移量。

fromXDelta = 0 //no offset. 
fromXDelta = 300 //the movement starts at 300px to the right.
fromXDelta = -300 //the movement starts at 300px to the left

toXDelta 定义移动在 X 轴上的偏移结束位置。

toXDelta = 0 //no offset. 
toXDelta = 300 //the movement ends at 300px to the right.
toXDelta = -300 //the movement ends at 300px to the left.

如果文本的宽度大于 fromXDelta 和 toXDelta 之间的差异模块,则文本将无法在屏幕内完全移动。


例子

假设我们的屏幕尺寸是 320x240 像素。我们有一个文本视图,其文本宽度为 700 像素,我们希望创建一个“拉动”文本的动画,以便我们可以看到短语的结尾。

                                       (screen)
                             +---------------------------+
                             |<----------320px---------->|
                             |                           |
                             |+---------------------------<<<< X px >>>>
               movement<-----|| some TextView with text that goes out...
                             |+---------------------------
                             |  unconstrained size 700px |
                             |                           |
                             |                           |
                             +---------------------------+


                             +---------------------------+
                             |                           |
                             |                           |
               <<<< X px >>>>---------------------------+|
movement<----- some TextView with text that goes out... ||
                             ---------------------------+|
                             |                           |
                             |                           |
                             |                           |
                             +---------------------------+

首先,我们设置fromXDelta = 0使运动没有起始偏移。现在我们需要计算 toXDelta 值。为了达到预期的效果,我们需要将文本“拉”出与屏幕外完全相同的像素。(在方案中用<<<< X px >>>>表示)由于我们的文本有700的宽度,可见区域是320px(屏幕宽度)我们设置:

tXDelta = 700 - 320 = 380

我们如何计算屏幕宽度和文本宽度?


代码

以 Zarah Snippet 为起点:

    /**
     * @param view The Textview or any other view we wish to apply the movement
     * @param margin A margin to take into the calculation (since the view
     *               might have any siblings in the same "row")
     *
     **/
public static Animation scrollingText(View view, float margin){

    Context context = view.getContext(); //gets the context of the view

            // measures the unconstrained size of the view
            // before it is drawn in the layout
    view.measure(View.MeasureSpec.UNSPECIFIED, 
                         View.MeasureSpec.UNSPECIFIED); 

            // takes the unconstrained wisth of the view
    float width = view.getMeasuredWidth();

            // gets the screen width
    float screenWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();


            // perfrms the calculation
    float toXDelta = width - (screenWidth - margin);

            // sets toXDelta to 0 if the text width is smaller that the screen size
    if (toXDelta < 0) {toXDelta = 0; } else { toXDelta = 0 - toXDelta;}

            // Animation parameters
    Animation mAnimation = new TranslateAnimation(0, toXDelta, 0, 0);
    mAnimation.setDuration(15000); 
    mAnimation.setRepeatMode(Animation.RESTART);
    mAnimation.setRepeatCount(Animation.INFINITE);

    return mAnimation;
}

可能有更简单的方法来执行此操作,但这适用于您可以想到的每个视图并且是可重用的。如果您想在 ListView 中为 TextView 设置动画而不破坏 textView 的启用/onFocus 功能,则它特别有用。即使视图没有聚焦,它也会连续滚动。

于 2010-12-09T10:48:29.770 回答
12

我不知道你是否还需要答案,但我找到了一个简单的方法来做到这一点。

像这样设置你的动画:

Animation mAnimation = new TranslateAnimation(START_POS_X, END_POS_X, 
                START_POS_Y, END_POS_Y);
mAnimation.setDuration(TICKER_DURATION); 
mAnimation.setRepeatMode(Animation.RESTART);
mAnimation.setRepeatCount(Animation.INFINITE);

START_POS_X, END_POS_X,START_POS_YEND_POS_Yfloat值,而ITICKER_DURATIONint用我的其他常量声明的。

然后您现在可以将此动画应用于您的 TextView:

TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);

就是这样。:)

我的动画从右侧屏幕外 (300f) 开始,在左侧屏幕外 (-300f) 结束,持续时间为 15 秒 (15000)。

于 2010-08-12T07:13:18.723 回答
5

我为带有选取框文本项的 ListView 编写了以下代码。它基于上述的 setSelected 解决方案。基本上,我正在扩展 ArrayAdapter 类并覆盖 getView 方法以在返回之前选择 TextView:

    // Create an ArrayAdapter which selects its TextViews before returning      
    // them. This would enable marqueeing while still making the list item
    // clickable.
    class SelectingAdapter extends ArrayAdapter<LibraryItem>
    {
        public
        SelectingAdapter(
            Context context, 
            int resource, 
            int textViewResourceId, 
            LibraryItem[] objects
        )
        {
            super(context, resource, textViewResourceId, objects);
        }

        @Override
        public
        View getView(int position, View convertView, ViewGroup parent)
        {
            View view = super.getView(position, convertView, parent);
            TextView textview = (TextView) view.findViewById(
                R.id.textview_playlist_item_title
            );
            textview.setSelected(true);
            textview.setEnabled(true);
            textview.setFocusable(false);
            textview.setTextColor(0xffffffff);
            return view;

        }
    }
于 2012-01-19T10:09:21.843 回答
1

这是在我的谷歌搜索顶部弹出的答案,所以我想我可以在这里发布一个有用的答案,因为我经常难以记住这一点。无论如何,这对我有用,需要 XML 属性和一个 onFocusChangeListener。

//XML
        <TextView
            android:id="@+id/blank_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:layout_gravity="center_horizontal|center_vertical"
            android:background="#a4868585"
            android:textColor="#fff"
            android:textSize="15sp"
            android:singleLine="true"
            android:lines="1"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit ="marquee_forever"
            android:scrollHorizontally="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            tools:ignore="Deprecated" />

//JAVA
    titleText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                titleText.setSelected(true);
            }
        }
    });
于 2016-12-29T19:16:38.390 回答
1

// xml

 <TextView
            android:id="@+id/tvMarque"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:layout_gravity="center_horizontal"
            android:fadingEdge="horizontal"
            android:marqueeRepeatLimit="marquee_forever"
            android:scrollHorizontally="true"
            android:padding="5dp"
            android:textSize="16sp"
            android:text=""
            android:textColor="@color/colorSyncText"
            android:visibility="visible" />

// 在 Java 中

        mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        mtvMarque.setSelected(true);
        mtvMarque.setSingleLine(true);
于 2018-12-05T13:13:43.423 回答