Reputation: 1480
I want to implement a recyclerview within a vertical viewpager. My current layout looks like the following
VerticalViewpager
- Fragment1
- ImageView
- Fragment2
- RecyclerView
If I swipe from Fragment1 to Fragment2 everything works fine. I am able to scroll within the recyclerview up and down. The problem occurs if I try to swipe/scroll back to Fragment1.
If the user has scrolled to the top of the recyclerview, I would like to forward the next "Up"-Scroll event to the vertical viewpager. I have tried overriding the onInterceptTouchEvent
method, but unfortunately still no success. Any ideas out there? Thanks for your help :)
Upvotes: 13
Views: 4498
Reputation: 876
I would suggest migrating to ViewPager2 first, since it natively allows for vertical scrolling, and then using the solution provided by the official documentation to supported nested scrollable elements.
Essentially, you need to add the NestedScrollableHost to your project and then wrap your RecyclerView with it, similar to below:
<NestedScrollableHost
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />
</NestedScrollableHost>
Note that this solution only works for the layout your provided where the RecyclerView would be an immediate child of one of your ViewPager's screen. This solution won't work for other RecyclerView that are nested in the main RecyclerView.
Upvotes: 1
Reputation: 158
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled (RecyclerView recyclerView,int dx, int dy) {
}
@Override
public void onScrollStateChanged (RecyclerView recyclerView,int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!mRecyclerView.canScrollVertically(-1) && newState == 0) {
Log.e("canScrollVertically", mRecyclerView.canScrollVertically(-1)+"");
verticalViewPager.setCurrentItem(0, true);
}
}
});
Upvotes: 0
Reputation: 86
I had the same problem. The answer from Mr.India was helpful, but as your commented, it only worked sometimes.
What I did was
recyclerView.setOnTouchListener(new View.OnTouchListener() {
public float speed;
public VelocityTracker mVelocityTracker;
@Override
public boolean onTouch(View v, MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
if(mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
else {
mVelocityTracker.clear();
}
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
if(mVelocityTracker != null) {
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
speed = VelocityTrackerCompat.getYVelocity(mVelocityTracker, pointerId);
}
break;
case MotionEvent.ACTION_UP:
int topRowVerticalPosition = (recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop();
if(speed > 500 && topRowVerticalPosition >= 0) {
ReaderFragmentParent parent = (ReaderFragmentParent) getActivity();
ReaderPager pager = parent.getPager();
if(pager != null) {
pager.setCurrentItem(pager.getCurrentItem()-1);
}
}
return false;
case MotionEvent.ACTION_CANCEL:
mVelocityTracker.recycle();
break;
}
return false;
}
});
On the ACTION_UP I verify if the speed > 500, it means it's going up on a considered speed and the topRowVerticalPosition means it is on top of the recyclerview. Then I get the ViewPager and setCurrentItem to previous item.
it's a bit of a dirty hack, but it was the only way I found to make look like a good scrolling between pages on the Vertical ViewPager
Upvotes: 0
Reputation: 17
You need to forbid nestedscroll in parent scrollview i have new implement for this , you can try the below link https://github.com/liuxiaocong/VerticalViewpage
Upvotes: 0
Reputation: 3539
1) You need to use support library 23.2.0 (or) above 2) and recyclerView height will be wrap_content. 3) recyclerView.setNestedScrollingEnabled(false)
But by doing this the recycler pattern don't work. (i.e all the views will be loaded at once because wrap_content needs the height of complete recyclerView so it will draw all recycler views at once. No view will be recycled). Try not to use this pattern util unless it is really required.
Upvotes: 2
Reputation: 382
If you have access VerticalViewPager
from RecyclerView, you can extend RecyclerView and check canScrollVertically(-1)
and forward touch event to viewpager
Upvotes: 1
Reputation: 1073
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled (RecyclerView recyclerView,int dx, int dy) {
int topRowVerticalPosition = (recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop();
if (topRowVerticalPosition >= 0) {
//top position
}
}
@Override
public void onScrollStateChanged (RecyclerView recyclerView,int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
By using this code you can find whether the user is in top position. In the position you can make the view pager to move to your desired position.
Upvotes: 1
Reputation: 674
You need do disable the scroll
. Try using recyclerView.setNestedScrollingEnabled(false);
Upvotes: 3