TextView的设置会停止其他TextView的选框滚动

时间:2011-09-03 17:43:46

标签: android scroll marquee

其他地方也问过,但解决方案对我不起作用。所以用更多的背景再次构成它。问题是活动包含滚动的音乐标题文本视图,该视图被更新的经过时间计数器文本视图中断。

我的活动布局中有这两个TextView小部件(尽管它们被其他布局容器包含)。

<TextView android:id="@+id/v_current_time"
   android:minWidth="26dp"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="center_vertical"
   android:gravity="right|center_vertical"
   android:singleLine="true"
   android:textSize="12sp"
   android:enabled="false"
  />

<TextView android:id="@+id/v_track_title"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:textSize="18sp"
   android:textStyle="normal"
   android:singleLine="true"
   android:ellipsize="marquee"
   android:marqueeRepeatLimit="marquee_forever"
   android:scrollHorizontally="true"
   android:focusable="true"
   android:focusableInTouchMode="true"
   android:enabled="true"
/>

音乐标题动态设置为(在测试用例中)一长行文本。如果我从未使用以下行更新当前时间的文本,则无论我如何与暂停和播放按钮进行交互,音乐标​​题都将永远滚动。

tvCurrentTime.setText(DataFormat.formatTime(progress));

但如果我确定当前时间的文字,音乐标题将会停止。按下我的暂停按钮会以某种方式将滚动回到齿轮,但按下播放将导致当前时间更新并再次停止。

根据这个帖子中的建议,我尝试将时间文本的设置与重新启用滚动标题结合起来,如下所示:

tvCurrentTime.setText(DataFormat.formatTime(progress));
tvTitle.setEnabled(true);

除了每次重新启动时重置滚动条以外,这对失败没有影响。

是否有一些我遗漏的细节,或者有什么可能出错的其他想法?非常感谢!

5 个答案:

答案 0 :(得分:7)

Marquee是有问题的。当TextView(或包含TextView的Window)失去焦点时,选取框将停止并重置(请参阅TextView的源)。 我想你在这里有3个可能的解决方案:

  1. 您可以在布局中的所有其他视图中设置android:focusable="false"。这样你的TextView就不会失去焦点。但这可能不是你想要的解决方案。
  2. 您可以对TextView进行子类化,并更改onFocusChanged()onWindowFocusChanged(),以防止停用和重置字幕。
  3. 创建自己的marquee实现。

答案 1 :(得分:6)

还有另一种解决方法,无需删除所有RelativeLayout。

您可以简单地将带有LinearLayout的选框TextView作为容器包装在RelativeLayout中。

答案 2 :(得分:2)

(将上面的评论推广到答案)结果证明上面的TextView XML配置工作正常,没有任何运行时更改(重置enabled = true或其他)如果我摆脱了布局文件中的RelativeLayout&将它们替换为LinearLayout&#39; s。如果我不这样做,上面的建议1或2(不确定3)都不起作用。这似乎是RelativeLayout的一个微妙而虚假的无证故障。

答案 3 :(得分:0)

在java代码中,执行tvTitle.setSelected(true);(这里,tvTitle是你的滑动TextView变量)对我有用。这样做,似乎再次集中精力。所以像魅力一样工作。

答案 4 :(得分:0)

我们有一个具有多种视图类型的适配器,第一个项目是带有选取框 TextView 的一个。滚动回屏幕顶部后,文本未显示(我们已调用 textView.isSelected == true)。

另外,问题不在于RelativeLayout,没有必要用LinearLayout包裹TextView,因为当前的布局结构是:

RelativeLayout
     Button
     TextView

下面是从 TextView 开始选取框的方法:

private void startMarquee() {
    // Do not ellipsize EditText
    if (getKeyListener() != null) return;

    if (compressText(getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight())) {
        return;
    }

    if ((mMarquee == null || mMarquee.isStopped()) && (isFocused() || isSelected())
            && getLineCount() == 1 && canMarquee()) {

        if (mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
            mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_FADE;
            final Layout tmp = mLayout;
            mLayout = mSavedMarqueeModeLayout;
            mSavedMarqueeModeLayout = tmp;
            setHorizontalFadingEdgeEnabled(true);
            requestLayout();
            invalidate();
        }

        if (mMarquee == null) mMarquee = new Marquee(this);
        mMarquee.start(mMarqueeRepeatLimit);
    }
}

需要视图有焦点或被选中才能开始选取框。

在 TextView.onFocusChanged(...) 中调用 startStopMarquee(focused) 方法,它将触发滚动动画。这种方法存在的问题是我们需要使用 postDelayed 请求焦点,这可能会导致一些问题。

在检查 TextView.setSelected(boolean) 方法在做什么之后,很清楚为什么 textView.isSelected = true 没有触发动画。在它内部,它正在检查之前的 isSelected 状态,如果新的 isSelected 状态与之前的状态不同,它将处理 startMarquee() 或 stopMarquee()。

解决方案是将选定状态更改为 false,然后将其设置为 true,效果很好。

以下是 setSelected 和 onFocusChanged 两种方法。

@Override
public void setSelected(boolean selected) {
    boolean wasSelected = isSelected();

    super.setSelected(selected);

    if (selected != wasSelected && mEllipsize == TextUtils.TruncateAt.MARQUEE) {
        if (selected) {
            startMarquee();
        } else {
            stopMarquee();
        }
    }
}

@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
    if (isTemporarilyDetached()) {
        // If we are temporarily in the detach state, then do nothing.
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        return;
    }

    if (mEditor != null) mEditor.onFocusChanged(focused, direction);

    if (focused) {
        if (mSpannable != null) {
            MetaKeyKeyListener.resetMetaState(mSpannable);
        }
    }

    startStopMarquee(focused);

    if (mTransformation != null) {
        mTransformation.onFocusChanged(this, mText, focused, direction, previouslyFocusedRect);
    }

    super.onFocusChanged(focused, direction, previouslyFocusedRect);
}