Stop ScrollView from setting focus on EditText

AndroidFocusAndroid EdittextScrollview

Android Problem Overview


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>

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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"

Solution 3 - Android

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'.

Solution 4 - Android

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

Solution 5 - Android

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

Solution 6 - Android

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)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser123321View Question on Stackoverflow
Solution 1 - Androiduser123321View Answer on Stackoverflow
Solution 2 - AndroidIonut NegruView Answer on Stackoverflow
Solution 3 - AndroidJack Ma nongView Answer on Stackoverflow
Solution 4 - AndroidnikhilView Answer on Stackoverflow
Solution 5 - AndroidUltimo_mView Answer on Stackoverflow
Solution 6 - AndroiducMediaView Answer on Stackoverflow