user123321
user123321

Reputation: 12783

Stop ScrollView from setting focus on EditText

Android's ScrollView (when scrolled or fling'd) likes to set the focus of an EditText when it's one of it's children. It happens when you scroll and then release. Is there anyway to stop this behavior? I've tried nearly everything I can think of and everything I've read on StackOverflow. Nothing has worked for me. Below is an example layout If you'd like to test it out. I'm desperate to stop this dumb behavior.

<?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>

Upvotes: 51

Views: 33996

Answers (6)

ucMax
ucMax

Reputation: 5428

It maybe too late but for the sake of others who have the same problem :

    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);
            }
        }
    });

Another way is to use NestedScrollView instead of ScrollView. (Recommended)

Upvotes: 0

Ultimo_m
Ultimo_m

Reputation: 4897

If none of the answers works, I would suggest to use:

yourView.post {
    yourView.requestFocus()
    scrollView.scrollY = 0
}

This way the scrollView will go back scroll 0 in case you need to scroll to start.

If not then you need to change it to the proper coordinate

Upvotes: 0

nikhil
nikhil

Reputation: 31

I just added a scroll listener and got the focused view from the activity and checked if it's visible in the scroll view or if it's scrolled beyond the screen and if it is scrolled beyond the screen, I just clear the focus on the view

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()
            }
        }

Upvotes: 3

Jack Ma nong
Jack Ma nong

Reputation: 51

ah it is very late. But I still want to add this solution to help newbies like me.

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

yes it works, just set a listener to clearfocus. and it is better than ing requestFocusFromTouch to another view 'x', which will lead to the same problem-- srolling to the view 'x'.

Upvotes: 5

Ionut Negru
Ionut Negru

Reputation: 6314

First, you can remove the parent of the ScrollView. Second, add focus options for the child(only one child per ScrollView):

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

This is how your xml should look like:

<?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>

Also, notice that you have multiple id's with the same name. Try giving them unique names.


If you want only to hide the soft-keyboard, and let the EditText still have it's focus, you can do this by adding the following property to your activity in manifest:

android:windowSoftInputMode="stateHidden"

Upvotes: 30

user123321
user123321

Reputation: 12783

This works. Not sure if it's the best solution or not.

// 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;
        }
    });

Upvotes: 116

Related Questions