Android:ScrollView内按钮改背景色触发自动滚顶问题
这个坑我之前踩过!你遇到的问题本质是:setBackground()(或setBackgroundColor())会触发按钮的重测量与布局更新,如果按钮所在的横向LinearLayout尺寸因此发生变化,ScrollView检测到内容区域高度改变后,会默认滚动到内容顶部——移除背景修改代码就正常,也刚好印证了这一点。
给你几个实用的解决方案:
方案一:手动记录并恢复滚动位置
在修改按钮背景前,先保存ScrollView当前的滚动偏移量,等背景设置完成后再滚回去。注意要用post()延迟执行恢复操作,确保布局更新完成后再生效:// 记录当前滚动位置 int currentScrollY = yourScrollView.getScrollY(); // 修改按钮状态与背景 button.setEnabled(false); button.setBackgroundColor(ContextCompat.getColor(context, R.color.your_target_color)); // 恢复滚动位置 yourScrollView.post(() -> yourScrollView.scrollTo(0, currentScrollY));方案二:用背景着色替代直接设置背景
改用ViewCompat.setBackgroundTintList()修改按钮颜色,这种方式不会改变View的尺寸,也就不会触发ScrollView的滚动行为,还能保留按钮原有背景Drawable的形状(比如圆角):// 设置按钮启用/禁用状态 button.setEnabled(false); // 修改背景色,不触发布局变化 ViewCompat.setBackgroundTintList(button, ColorStateList.valueOf(ContextCompat.getColor(context, R.color.your_target_color)));如果需要区分按钮的启用/禁用状态颜色,可以创建带状态的
ColorStateList:<!-- res/color/button_reaction_tint.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/reaction_enabled" android:state_enabled="true"/> <item android:color="@color/reaction_disabled" android:state_enabled="false"/> </selector>然后在代码里直接引用:
ViewCompat.setBackgroundTintList(button, ContextCompat.getColorStateList(context, R.color.button_reaction_tint));方案三:固定ScrollView内容区域高度
给ScrollView的直接子View设置固定高度,或者开启fillViewport="true"让子View填满ScrollView的视口,这样即使按钮尺寸变化,整个内容区域高度不会改变,ScrollView就不会触发自动滚动:<ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <!-- 直接子View设置match_parent,确保高度固定 --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 你的其他布局,包括inc_reactions_buttons --> </LinearLayout> </ScrollView>
另外可以额外排查下:你的按钮原背景是不是带有自适应尺寸的属性(比如wrap_content的高度),修改背景后按钮高度变化,才导致整个内容区域高度改变。如果是这种情况,给按钮设置固定高度也能快速解决问题。
内容的提问来源于stack exchange,提问作者GneGneGne

