阻止ScrollView在EditText上设置焦点

51

当Android的ScrollView被滚动或快速滑动时,它会喜欢将焦点设置在其子节点中的EditText上。这种情况发生在您滚动然后释放时。有没有办法停止这种行为?我已经尝试了我所能想到的一切,也阅读了StackOverflow上的所有内容,但仍无法解决。以下是一个示例布局,如果您想测试它。我渴望停止这种愚蠢的行为。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<ScrollView 
    android:id="@+id/scrollView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

<LinearLayout 
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginRight="50dp"
    android:focusable="true"
    android:focusableInTouchMode="true"
    >

    <EditText 
        android:layout_width="fill_parent" 
        android:layout_height="100dp" 
        android:text="TestApp 1"
        />


    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <EditText 
        android:layout_width="fill_parent" 
        android:layout_height="100dp" 
        android:text="Bleh...."
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />
    <EditText 
        android:layout_width="fill_parent" 
        android:layout_height="100dp" 
        android:text="TestApp 1"
        />


    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="MeeEEEEEEEEEEEEE"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />



</LinearLayout>
</ScrollView>

</LinearLayout>
6个回答

116

这个可以用。不确定是否是最好的解决方案。

// SCROLL VIEW HACK
    // BOGUS
    ScrollView view = (ScrollView)findViewById(R.id.scrollView);
    view.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
    view.setFocusable(true);
    view.setFocusableInTouchMode(true);
    view.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            v.requestFocusFromTouch();
            return false;
        }
    });

只有这段代码完全按照我想要的方式工作。 - Taimur Hassan
喜欢这个答案。 - Jimit Patel
经过漫长的时间,终于找到了解决方案。 - Nauman Ash
1
这会将焦点放在整个“ScrollView”上,并导致背景颜色发生奇怪的变化。 - Debdeep
1
@Debdeep,我找到了一个解决方案...不要使用v.requestFocusFromTouch(),而是使用v.requestFocus(),它仍然可以完美地工作,而且背景颜色不会受到影响。干杯 :) - Alex Rivas
显示剩余3条评论

30

首先,您可以删除ScrollView的父级。 其次,为子元素添加焦点选项(每个ScrollView仅限一个子元素):

android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true"

这是你的xml应该看起来的样子:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginRight="50dp"
        android:descendantFocusability="beforeDescendants"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/editText_one"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_two"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_three"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <EditText
            android:id="@+id/editText_two"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="Bleh...." />

        <Button
            android:id="@+id/btn_four"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <EditText
            android:id="@+id/editText_three"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_five"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_six"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="MeeEEEEEEEEEEEEE" />

        <Button
            android:id="@+id/btn_seven"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />
    </LinearLayout>

</ScrollView>

此外,请注意您有多个具有相同名称的ID。尝试为它们提供唯一的名称。


如果您只想隐藏软键盘,并使EditText仍然保持其焦点,则可以通过在manifest中的活动中添加以下属性来实现:

android:windowSoftInputMode="stateHidden"

将可聚焦属性 focusable、focusableInTouchMode=true 和 descendantFocusability 添加到 ScrollView 的直接子元素上,这对我很有效。谢谢! - reavcn

5

噢,现在很晚了。但我还是想分享这个解决方案,来帮助像我一样的新手。

ScrollView sv = (ScrollView)findViewById(R.id.scrollView);
sv.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            sv.clearFocus();
            return false;
        }
    });

没问题,只需设置侦听器以清除焦点即可。这比使用requestFocusFromTouch方法切换到另一个视图“x”更好,后者会导致相同的问题——滚动到视图“x”。


这是最好的答案。如果您有一个复杂的视图,其中包含滚动视图内的多个视图以及回收站视图。这个clearFocus()会清除父视图和每个子视图的焦点。谢谢..你救了我的一天。 <3 - Satyajit

3

我刚刚添加了一个滚动监听器,并从活动中获取了焦点视图,并检查它是否在滚动视图中可见,或者是否已经滚动到屏幕之外,如果它已经滚动到屏幕之外,我就清除了该视图上的焦点

setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
            val focusedView = (context as? FragmentActivity)?.currentFocus
            val viewRect = Rect()
            this.getHitRect(viewRect)

            if(focusedView?.getLocalVisibleRect(viewRect) == false) {
                focusedView.clearFocus()
            }
        }

1
这是我个人经验中最好的答案。其他答案还存在一些无法接受的奇怪行为。 - Pilot_51

0
如果没有任何答案可行,我建议使用以下方法:
yourView.post {
    yourView.requestFocus()
    scrollView.scrollY = 0
}

这样scrollView就会回到滚动位置0,以防需要滚动到开头。

如果不是,则需要将其更改为正确的坐标。


0

也许已经有点晚了,但是为了那些遇到同样问题的人着想:

    scrollView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
    scrollView.setFocusable(true);
    scrollView.setFocusableInTouchMode(true);
    scrollView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    });

另一种方法是使用NestedScrollView而不是ScrollView。(推荐


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接