51

When I put a RecyclerView inside a nested scrollview, the screen always jumps to the top of the RecyclerView instead of the top of the page. Here is a simple example.

layout xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="350dp"
            android:background="@android:color/holo_blue_dark"/>
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycleView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>
</layout>

Activity with dummy adapter:

public class RecycleViewTestActivity extends AppCompatActivity {

public static class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {

    private Context context;

    public ExampleAdapter(Context context) {
        this.context = context;
    }

    @Override
    public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        TextView view = new TextView(context);
        view.setText("Test");
        return new ExampleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ExampleViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 100;
    }
}

public static class ExampleViewHolder extends RecyclerView.ViewHolder {

    public ExampleViewHolder(View itemView) {
        super(itemView);
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_rectest);
    RecyclerView view = (RecyclerView) findViewById(R.id.recycleView);
    view.setNestedScrollingEnabled(false);
    view.setLayoutManager(new LinearLayoutManager(this));
    ExampleAdapter adapter = new ExampleAdapter(this);
    view.setAdapter(adapter);
}

}

In this example I have a 350dp tall empty view over the recycleview because you need to have some content over the RecycleView for this to show up obviously. The RecycleView iteself contains 100 dummy textviews.

After you start the activity, the scroll is at the top of the RecycleView instead of the top of the page. It must be something inside the LinearLayoutManager, but havent really looked yet.

Any ideas how to solve this?

kame
  • 20,848
  • 33
  • 104
  • 159
breakline
  • 5,776
  • 8
  • 45
  • 84

5 Answers5

147

Make your top view focusable. "RecyclerView has "focusableOnTouchMode" set to true to handle its childrens' focus changes during layout." Relevant discussion of the issue.

Example:

<android.support.v4.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusableInTouchMode="true"
        android:orientation="vertical">

        <View
            android:id="@+id/someView"
            android:layout_width="wrap_content"
            android:layout_height="350dp"/>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </LinearLayout>
</android.support.v4.widget.NestedScrollView>
Jim Pekarek
  • 7,270
  • 6
  • 33
  • 34
  • 3
    That worked for me as well. Just put: android:focusable="true" android:focusableInTouchMode="true" in any view that is parent of your RecyclerView and that should solve it. – Roberto Jul 14 '16 at 15:43
  • Below is my solution android:descendantFocusability="blocksDescendants" to parent of recyclerview. – maruti060385 Aug 04 '17 at 16:45
  • Hi Lancelot, I did that exactly but unfortunately it still does not work. I got the exact same problem as the requester, I tried everything, I posted also a question https://stackoverflow.com/questions/75162652/recyclerview-in-nested-scrollview-gets-unwanted-focus for this but no one seems to have an answer. – Simon Jan 19 '23 at 08:34
34

For me accepted answer didn't work. I solve this by adding this attribute for parent:

android:descendantFocusability="blocksDescendants"

dr-to-str
  • 349
  • 3
  • 3
  • it worked for me. I was using recycler view in scroll view. thanks – Gulnaz Ghanchi Aug 17 '17 at 06:06
  • I had same layout as @GulnazGhanchi. This worked for me :-) – Abhijit Kurane Jan 30 '18 at 08:10
  • Great, this also works when having Horizontal RecyclerView(s) inside a Vertical RecyclerView. The item would steal focus when data was bind and cause the list to do small "jumps" that decreased performance. Works like a charm to add android:descendantFocusability="blocksDescendants" to the root of the Horizontals ReyclerView layout. – Slickelito Feb 19 '18 at 10:37
  • this one works for me, horizontal recycler view inside vertical recycler view – diousk Apr 30 '18 at 10:17
  • 2
    This may be an issue if you want to support keyboard navigation in your app – Itay Karo Feb 14 '19 at 09:55
  • thanks, this one works for the case the RecyclerView have VideoView (SimpleExoPlayerView) as item but the accepted answer doesn't. – Phong Nguyen May 30 '19 at 11:06
  • 1
    blocksDescendants means we are blokcing focusing feature of descendant and we can't interact with EditText etc – Zaid Mirza Jul 30 '19 at 05:32
  • blocksDescendants can solve the problem yes but when you use it you should be careful Because If you have any edittext in it, edittext dont be focusable and keyboard dont open – Kadir altınok Nov 14 '19 at 10:42
  • This was a big fix for our accessibility. It kept stealing focus when I updated View.GONE to View.VISIBLE on the RecyclerView. Took me a few hours to figure out it was this! Thank you! – Alan Nelson Mar 20 '20 at 16:55
  • This is not good practice if you have SearchView widget inside nestedScrollView. Because this snippet code will block focus of editing text – Aldy Jun 09 '21 at 09:34
5

Thanks @Amagi82. You answer helped me but it was not enough. I added more 2 attributes. That worked for me:

<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusableInTouchMode="true"
    android:focusable="true"
    android:descendantFocusability="blocksDescendants"
    android:orientation="vertical">

    <View
        android:id="@+id/someView"
        android:layout_width="wrap_content"
        android:layout_height="350dp"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

André Luiz Reis
  • 2,273
  • 21
  • 14
  • blocksDescendants means we are blokcing focusing feature of descendant and we can't interact with EditText etc – Zaid Mirza Jul 30 '19 at 05:32
5

using android:descendantFocusability="blocksDescendants" very dangerous. Because it blocks opening keyboard. For example at the same page you use edittext and you solve the problem using blocksDescendants. and you click the edittext, keyboard will not open. For this reason, you should use android:focusableInTouchMode="true" in root view in NestedScrollView.

Kadir altınok
  • 230
  • 2
  • 5
1

Do it this way:

LinearLayoutManager lm = new LinearLayoutManager(this);
lm.setAutoMeasureEnabled(true);
view.setLayoutManager(lm)
Chris Sherlock
  • 931
  • 5
  • 19