其他地方也问过,但解决方案对我不起作用。所以用更多的背景再次构成它。问题是活动包含滚动的音乐标题文本视图,该视图被更新的经过时间计数器文本视图中断。
我的活动布局中有这两个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);
除了每次重新启动时重置滚动条以外,这对失败没有影响。
是否有一些我遗漏的细节,或者有什么可能出错的其他想法?非常感谢!
答案 0 :(得分:7)
Marquee是有问题的。当TextView(或包含TextView的Window)失去焦点时,选取框将停止并重置(请参阅TextView的源)。 我想你在这里有3个可能的解决方案:
android:focusable="false"
。这样你的TextView就不会失去焦点。但这可能不是你想要的解决方案。 onFocusChanged()
和onWindowFocusChanged()
,以防止停用和重置字幕。答案 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);
}