13

I have construction where there are two items which are static and recyclerview with draggable items. Both types of view are wrapped by LinearLayout. LinearLayout is wrapped by NestedScrollView.

XML explanation:

<NestScrollView>
  <LinearLayout>
    <View></View>
    <View></View>
    <RecyclerView></RecyclerView>
  </LinearLayout>
</NestScrollView>

Pic explanation:

enter image description here

Implementation of dragging items I took from this tutorial: https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.yc7me2ikf

The problem is the RecyclerView doesn't scroll when I drag his children out of screen. (However if I don't have NestedScrollView as a parent, RecyclerView works as expected.)

I searched every problem related to this but I didn't find any solution.

Vishal Chhodwani
  • 2,457
  • 5
  • 24
  • 37
deadfish
  • 11,064
  • 11
  • 79
  • 125
  • agree with answer below, its not a good practice. Please try to change your approach. – Deep Patel Mar 08 '17 at 12:39
  • Have you added NestedScrollingEnabled=false in your recyclerView? – Basu Mar 17 '17 at 06:29
  • I would suggest you to get rid of nested scrollview, put the textviews in a parent view and add that view as header in recyclerView. Here's how to add header to recyclerview (http://stackoverflow.com/questions/26448717/android-5-0-add-header-footer-to-a-recyclerview) – Deepak Negi Mar 17 '17 at 11:24
  • 2
    Did you end up finding a solution? My collapsing toolbar won't work without the nestedscrollview – behelit Jan 14 '18 at 22:17
  • has anyone tried to override interpolateOutOfBoundsScroll? – Rahmat Ihsan Mar 04 '19 at 08:45
  • There isn't a simple method of triggering scrolling in a parent view, and to understand why I suggest taking a look at the scrollIfNecessary() method of ItemTouchHelper. The implemented scrolling happens basically in two steps: 1. Determining whether user drags the item to the edge of the view. 2. Scrolling the view (assuming the view is scrollable). Ideally we would like to manually determine the view mentioned in those two steps (and setting it to our root NestedScrollView) but in the ItemTouchHelper implementation that view is hardcoded as the decorated RecyclerView. – Werek Feb 05 '21 at 18:35

5 Answers5

0

Putting recyclerView inside NestedScrollView is not a good practice. I recommend you to use your other views as RecyclerView items. I'm sure that will fix your problem as you've said "However if I don't have NestedScrollView as a parent, RecyclerView works as expected."

Paresh P.
  • 5,913
  • 1
  • 11
  • 23
  • okay but I must have scroll and I must also have recyclerview – deadfish Mar 08 '17 at 12:35
  • 1
    @deadfish Wizard is right, you shouldn't put scrolling view inside scrolling view, same as you don't put listView inside scrollingView, it will cause problems – Janusz Hain Mar 13 '17 at 14:37
0

Make the NestedScrollView and RecyclerView play nice together by adding android:fillViewport="true" to the recycler

When you start to drag your item or once you reach the edge of the screen you can also turn off the recycler's nested behaviour with mRecyclerView.setNestedScrollingEnabled(false). This will cause the nested view itself to scroll so that the user continues down the recyclerview.

Once you're finished set nested scrolling to true again.

Alternatively you will need to look at delegating who gets the touch events like I outlined for another question here. For your sample it might be as simple as:

  • When drag starts call nestedScrollView.requestDisallowInterceptTouchEvent(true);
  • When drag ends requestDisallowInterceptTouchEvent(false) to reenable scrollview

If the requestDisallowInterceptTouchEvent fails to work, then you can create a subclass of NestedScrollView and override onInterceptTouchEvent like on my linked answer

Community
  • 1
  • 1
Nick Cardoso
  • 18,430
  • 9
  • 62
  • 110
0

I have faced the same problem. I use the other views as the recycler view.
First of all we have to return the two views in getItemViewType().

public int getItemViewType(int position)
{
if(position == 0)
{
return HEADERVIEW;
}   
return LISTVIEW;
}

Now, we are adding the other view as the HeaderView in the list so we are going to tweak the list count:

@Override public int getItemCount() 
{ 
       return arrayList.size()+1;
}

Now bind the views correctly in onBindViewHolder on the basis on the getItemViewType()

@Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) 
{
if(viewHolder.getItemViewType() == HEADERVIEW )
{
HeaderViewHolder headerViewHolder = (HeaderViewHolder)viewHolder;
headerViewHolder.headertextview.SetText("LongText");
}
else
{
MyHolder myHolder = (MyHolder) viewHolder;
myHolder.name.setText(arrayList.get(i-1).name);
}

Now in the Item Touch Listener Callback we have to tweak the onMove() method:

public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 
// get the viewHolder's and target's positions in your adapter data, swap them
if(viewHolder.getItemViewType() != target.getItemViewType())
{
return false; 
}
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
if(dragFrom == -1) 
{ 
dragFrom =  fromPosition; 
}
dragTo = toPosition;
if(dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) 
{
reallyMoved(dragFrom, dragTo);
dragFrom = dragTo = -1;
}
// and notify the adapter that its dataset has changed
adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());                
return true;
}

Now if all the logic is right then we move the item and call onreallyMoved() method:

private void reallyMoved(int dragFrom, int dragTo) 
{
if(dragFrom == 0 || dragTo == arrayList.size())
{
 return;
}
Collections.swap(arrayList, dragFrom-1, dragTo-1);
}

If you want to know more have a look at my blog post.

Baum mit Augen
  • 46,177
  • 22
  • 136
  • 173
Gopal Awasthi
  • 233
  • 4
  • 14
0

Another solution is to use a linearLayout instead the NestedScrollView. At its root, put the recyclerView, with parameter : sethasFixedSize(true) in your Java file, and with match_parent height as well in xml.

recap :

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

    <RecyclerView
        ...
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

 </LinearLayout>

don't forget to set recyclerView.setHasFixedSize(true); in your Java file

Arnaud
  • 218
  • 1
  • 7
-1

Go with something like:

       <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

       <android.support.v4.widget.NestedScrollView
            android:id="@+id/view_noRecord"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <TextView
                android:id="@+id/tv_no_record"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="top"
                android:layout_marginBottom="@dimen/_20sdp"
                android:gravity="center_horizontal"
                android:padding="@dimen/_10sdp"
                android:text="@string/no_data_found"
                android:visibility="gone"
                app:layout_behavior="@string/appbar_scrolling_view_behavior" />
        </android.support.v4.widget.NestedScrollView>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/common_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fadeScrollbars="true"
            android:scrollbars="vertical"
            android:visibility="gone"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />



    </FrameLayout>

Or try to this put content from your layout as a header of your RecyclerView

<LinearLayout>
    <View></View>
    <View></View>
  </LinearLayout>
Deep Patel
  • 2,258
  • 2
  • 12
  • 26
  • I could add headers to recyclerview but I don't want treat them as a children of the list. The whole layout must be scrollable. – deadfish Mar 08 '17 at 12:49
  • By adding header you can make the whole layout scrollable too, I had done the same in recent times. – Deep Patel Mar 08 '17 at 12:50