Android TextView权重与跑马灯:其他View更新时跑马灯重置问题求助
问题描述
我有一个水平方向的LinearLayout,内部包含两个TextView,要求它们始终可见。第一个TextView文本长度不固定,需要适配两种显示场景:
- 当第一个文本较长时:|[text1 long long lo...][text2]|
- 当第一个文本较短时:|[text1][text2]_______________|
我给第一个TextView设置了永久跑马灯动画,用layout_weight适配长文本场景,同时把LinearLayout宽度设为wrap_content适配短文本场景。但现在遇到问题:更新第二个TextView时,第一个TextView的跑马灯动画会重置,不符合需求。求可行的修复方案。
示例代码
<LinearLayout android:id="@+id/linearLayout" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/textViewFirst" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:fontFamily="@font/roboto_regular" android:textSize="32sp" android:text="May be a very very very long text view" android:lineHeight="37.504dp" android:singleLine="true" android:ellipsize="marquee" android:marqueeRepeatLimit="marquee_forever" /> <TextView android:id="@+id/textViewSecond" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/transparentWhite" android:fontFamily="@font/roboto_regular" android:textSize="32sp" android:text=" short text" android:lineHeight="37.504dp" /> </LinearLayout>
修复方案
方案1:自定义TextView控制跑马灯状态
系统默认TextView在布局重绘时会重置跑马灯,自定义一个MarqueeTextView手动管控状态,避免被布局更新打断:
class MarqueeTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : TextView(context, attrs, defStyleAttr) { private var isMarqueeRunning = false override fun onAttachedToWindow() { super.onAttachedToWindow() if (isMarqueeRunning) startMarquee() } override fun onDetachedFromWindow() { super.onDetachedFromWindow() isMarqueeRunning = isFocused && marquee != null && marquee.isRunning } fun startMarqueeManually() { isMarqueeRunning = true ellipsize = null ellipsize = TextUtils.TruncateAt.MARQUEE requestFocus() } fun stopMarqueeManually() { isMarqueeRunning = false marquee?.stop() } }
布局中替换原TextView为自定义类,初始化时调用startMarqueeManually()启动跑马灯,更新第二个TextView时不会影响第一个的动画状态。
方案2:调整LinearLayout布局参数避免重绘触发重置
原LinearLayout设为wrap_content,更新第二个TextView会触发整体布局重绘,改成match_parent并给第一个TextView动态设置maxWidth:
- 将LinearLayout的
android:layout_width改为match_parent - 动态计算第一个TextView的最大宽度:
textViewSecond.post { val parentWidth = linearLayout.width val secondTextWidth = textViewSecond.width textViewFirst.maxWidth = parentWidth - secondTextWidth - dpToPx(16) // 减去预留间距 }
这种方式减少布局重绘对第一个TextView的干扰,跑马灯不会被轻易重置,同时也能满足两种显示场景。
方案3:用ConstraintLayout替代LinearLayout
ConstraintLayout布局更新更高效,可精准控制两个TextView的关系,避免weight机制带来的重绘问题:
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textViewFirst" android:layout_width="0dp" android:layout_height="wrap_content" android:fontFamily="@font/roboto_regular" android:textSize="32sp" android:text="May be a very very very long text view" android:lineHeight="37.504dp" android:singleLine="true" android:ellipsize="marquee" android:marqueeRepeatLimit="marquee_forever" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/textViewSecond" app:layout_constraintHorizontal_bias="0" app:layout_constraintWidth_max="wrap" /> <TextView android:id="@+id/textViewSecond" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/transparentWhite" android:fontFamily="@font/roboto_regular" android:textSize="32sp" android:text=" short text" android:lineHeight="37.504dp" app:layout_constraintStart_toEndOf="@id/textViewFirst" app:layout_constraintEnd_toEndOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
该布局既满足长文本压缩显示跑马灯、短文本靠左排列的需求,又能避免更新第二个TextView时重置第一个的跑马灯。
内容的提问来源于stack exchange,提问作者Angelo Miguel
相关产品推荐
相关产品推荐

