如何阻止ScrollView在内部可选中TextView获焦点时滚动?
解决ScrollView嵌套可选TextView时自动滚动的问题
我之前碰到过一模一样的场景,这个问题的核心在于ScrollView默认会在子视图获取焦点时自动滚动到该视图,但我们又得保留TextView的文本选中功能(这依赖焦点才能工作),所以得找个平衡点。下面是最靠谱的解决方案:
自定义ScrollView拦截焦点触发的滚动
通过重写ScrollView的requestChildFocus方法,我们可以专门针对可选中的TextView做特殊处理——允许它获取焦点,但阻止ScrollView执行滚动逻辑:
public class NoFocusScrollScrollView extends ScrollView { public NoFocusScrollScrollView(Context context) { super(context); } public NoFocusScrollScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public NoFocusScrollScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void requestChildFocus(View child, View focused) { // 只拦截可选中TextView的焦点请求 if (focused instanceof TextView && ((TextView) focused).isTextSelectable()) { // 让TextView拿到焦点,但跳过ScrollView的滚动操作 focused.requestFocus(); return; } // 其他可聚焦控件(比如EditText)保持默认的滚动行为 super.requestChildFocus(child, focused); } }
布局中替换为自定义ScrollView
把原来布局里的ScrollView换成这个自定义类就行,TextView依旧保持android:textIsSelectable="true":
<com.yourpackage.NoFocusScrollScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 你的多个可选中TextView --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textIsSelectable="true" android:text="这里是可以选中复制的文本内容..." /> <!-- 其他子视图 --> </com.yourpackage.NoFocusScrollScrollView>
为什么这个方案能解决你的三个问题?
- 长按选中文本不再滚动:TextView获取焦点时不会触发ScrollView滚动,选中的文本会稳稳停在用户长按的位置,完全符合直觉。
- 双击手势正常识别:第一次触摸TextView时不会触发滚动,两次触摸都能被手势识别器捕获,不会因为滚动导致手势失效。
- 完整保留文本选中功能:我们没有禁用TextView的焦点,只是阻止了ScrollView的滚动逻辑,复制、分享、全选这些功能都能正常使用。
额外提醒
- 如果布局里有其他需要ScrollView滚动到的可聚焦控件(比如EditText),这个方案不会影响它们的正常行为,因为我们只拦截了可选中的TextView。
- 用Kotlin的话,把上面的Java代码转成Kotlin版本就行,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Adam Martinu
相关产品推荐
相关产品推荐

