ScrollView disable focus move

30,719

Solution 1

Just thought I'd share my solution to this. Even though some of the other answer's comments state that you cannot override this behavior, that is not true. This behavior stops as soon as you override the onRequestFocusInDescendants() method. So simply create your ScrollView extension to do this:

public class NonFocusingScrollView extends ScrollView {

  public NonFocusingScrollView(Context context) {
    super(context);
  }

  public NonFocusingScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public NonFocusingScrollView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  @Override
  protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
    return true;
  }

}

And you're done. The ScrollView will mess with your focus no more.

Solution 2

I have had such a problem too. The only way that helped me is to extend scroll view and to override neigher

@Override
public ArrayList<View> getFocusables(int direction) {
    return new ArrayList<View>();
}

or

@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
    return true;
}

but to override ViewGroup.requestChildFocus(View child, View focused) method as following:

    @Override
    public void requestChildFocus(View child, View focused) {
        // avoid scrolling to focused view
        // super.requestChildFocus(child, focused);
    }

Solution 3

What worked for me was combining @dmon's and @waj's answers.

Only overriding onRequestFocusInDescendants() worked great when I was only dealing with EditTexts inside of the ScrollView, but when I started added multiple View types, it didn't work so well.

Only overriding getFocusables() did not work at all.

Overriding both onRequestFocusInDescendants() AND getFocusables() seems to work beautifully in all scenarios.

public class FixedFocusScrollView extends ScrollView {

  public FixedFocusScrollView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  public FixedFocusScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public FixedFocusScrollView(Context context) {
    super(context);
  }

  @Override
  public ArrayList<View> getFocusables(int direction) {
      return new ArrayList<View>();
  }

  @Override
  protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
    return true;
  }

}

Solution 4

I tried all solutions posted here but either didn't work on certain Android versions or it messed up with some other behavior like when switching between touch and non-touch mode (when you click buttons or use the trackpad).

I finally found that overriding the method getFocusables did the trick:

public class FixedFocusScrollView extends ScrollView {

  public FixedFocusScrollView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  public FixedFocusScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public FixedFocusScrollView(Context context) {
    super(context);
  }

  @Override
  public ArrayList<View> getFocusables(int direction) {
    return new ArrayList<View>();
  }

}

Solution 5

Try to cut the problem from the source (edit: i.e. move it to an XML file).

First, there must be a focusable element for that to happen. Make all focusable elements contained in that scroll into non-focusable elements. Make them focusable after the view is inflated and is visible.

android:focusable="false"
android:focusableInTouchMode="false"
Share:
30,719
AlexKorovyansky
Author by

AlexKorovyansky

BY DAY: Co-founder and CTO at Effective. Founder and hacker at Mobilatorium. BY NIGHT: Google Developer Expert, speaker, event organizer, blogger.

Updated on September 02, 2020

Comments

  • AlexKorovyansky
    AlexKorovyansky over 3 years

    I have a simple input form; it's a vertical LinearLayout with EditTexts inside a ScrollView.

    <ScrollView android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <LinearLayout android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="vertical">
                <LinearLayout android:layout_width="fill_parent"
                      android:layout_height="wrap_content"
                      android:padding="10dip"
                      android:gravity="center_vertical"
                      android:orientation="horizontal">
                      <TextView style="@style/Text"
                             android:text="Name"/>
                      <EditText style="@style/EditBox"/>
                </LinearLayout>
                <View style="@style/Divider"/>
                <LinearLayout android:layout_width="fill_parent"
                      android:layout_height="wrap_content"
                      android:padding="10dip"
                      android:gravity="center_vertical"
                      android:orientation="horizontal">
                      <TextView style="@style/Text"
                             android:text="Password"/>
                      <EditText style="@style/EditBox"/>
                </LinearLayout>               
                ... 
         </LinearLayout>
    </ScrollView>
    

    When the user scrolls the form, it automatically moves its focus to the visible EditText. It is possible to disable such behavior and always keep focus on the EditText currently selected by touch?

    I understand that this may be a feature, but I need to disable it.

    Thanks!