Horizontal ScrollView inside Vertical RecyclerView inside Horizontal RecyclerView scrolling behavior
up vote
0
down vote
favorite
I have an Activity
below:
<RecyclerView> // with horizontal LinearLayoutManager and PagerSnapHelper
<RecyclerView> // with vertical LinearLayoutManager
<RecyclcerView /> // with horizontal LinearLayoutManager
<HorizontalScrollView />
// ... and there are other normal list items
</RecyclerView>
<RecyclerView> // another RV with vertical LinearLayoutManager
</RecyclerView>
</RecyclerView>
The problem is when I scroll horizontally, the inner horizontal RecyclerView
and HorizontalScrollView
doesn't scroll as expected.
Why I have to do this:
I have several ListFragment
s, each of which takes data from different data sources, but has same type of list items. I don't want a ViewPager
, which either hold all pages immediately after ViewPager
is created(which may cause OutOfMemoryError), or reload data from network after user scrolling to other pages and scroll back. Further more, with nested RV, pages can share one same RecyclerViewPool
, which helps to decrease total count of item views in all pages.
What I have done in the outer horizontal RV:
private static final int INVALID_POINTER = -1;
private int mActivePointerId = INVALID_POINTER;
private float lastX;
private GestureDetector mVerticalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) < Math.abs(distanceY);
}
});
private GestureDetector mHorizontalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) > Math.abs(distanceY);
}
});
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if (mVerticalScrollGestureDetector.onTouchEvent(e) || !mAllowPageScroll) {
return false;
}
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = e.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
int pointerIndex = e.findPointerIndex(mActivePointerId);
float x = e.getX(pointerIndex);
float dx = x - lastX;
lastX = x;
if (childCanScroll(this, false, (int) dx, (int) x)) {
Log.d("ScrollX", "not intercept");
return false;
}
Log.d("ScrollX", "maybe intercept");
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mActivePointerId = INVALID_POINTER;
break;
}
return super.onInterceptTouchEvent(e);
}
private boolean childCanScroll(View v, boolean considerSelf, int dx, int x) {
if (v instanceof ViewGroup) {
ViewGroup group = (ViewGroup) v;
int scrollX = v.getScrollX();
for (int i = group.getChildCount() - 1; i >= 0; i--) {
View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
&& childCanScroll(child, true, dx, x + scrollX - child.getLeft())) {
return true;
}
}
}
return considerSelf && v.canScrollHorizontally(-dx);
}
Now it works with inner horizontal RV with occasionally not scrolling, and doesn't work with HorizontalScrollView
at all.
How can I achieve the goal to make inner horizontally-scrollable view to scroll first?
android-recyclerview android-nestedscrollview
add a comment |
up vote
0
down vote
favorite
I have an Activity
below:
<RecyclerView> // with horizontal LinearLayoutManager and PagerSnapHelper
<RecyclerView> // with vertical LinearLayoutManager
<RecyclcerView /> // with horizontal LinearLayoutManager
<HorizontalScrollView />
// ... and there are other normal list items
</RecyclerView>
<RecyclerView> // another RV with vertical LinearLayoutManager
</RecyclerView>
</RecyclerView>
The problem is when I scroll horizontally, the inner horizontal RecyclerView
and HorizontalScrollView
doesn't scroll as expected.
Why I have to do this:
I have several ListFragment
s, each of which takes data from different data sources, but has same type of list items. I don't want a ViewPager
, which either hold all pages immediately after ViewPager
is created(which may cause OutOfMemoryError), or reload data from network after user scrolling to other pages and scroll back. Further more, with nested RV, pages can share one same RecyclerViewPool
, which helps to decrease total count of item views in all pages.
What I have done in the outer horizontal RV:
private static final int INVALID_POINTER = -1;
private int mActivePointerId = INVALID_POINTER;
private float lastX;
private GestureDetector mVerticalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) < Math.abs(distanceY);
}
});
private GestureDetector mHorizontalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) > Math.abs(distanceY);
}
});
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if (mVerticalScrollGestureDetector.onTouchEvent(e) || !mAllowPageScroll) {
return false;
}
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = e.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
int pointerIndex = e.findPointerIndex(mActivePointerId);
float x = e.getX(pointerIndex);
float dx = x - lastX;
lastX = x;
if (childCanScroll(this, false, (int) dx, (int) x)) {
Log.d("ScrollX", "not intercept");
return false;
}
Log.d("ScrollX", "maybe intercept");
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mActivePointerId = INVALID_POINTER;
break;
}
return super.onInterceptTouchEvent(e);
}
private boolean childCanScroll(View v, boolean considerSelf, int dx, int x) {
if (v instanceof ViewGroup) {
ViewGroup group = (ViewGroup) v;
int scrollX = v.getScrollX();
for (int i = group.getChildCount() - 1; i >= 0; i--) {
View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
&& childCanScroll(child, true, dx, x + scrollX - child.getLeft())) {
return true;
}
}
}
return considerSelf && v.canScrollHorizontally(-dx);
}
Now it works with inner horizontal RV with occasionally not scrolling, and doesn't work with HorizontalScrollView
at all.
How can I achieve the goal to make inner horizontally-scrollable view to scroll first?
android-recyclerview android-nestedscrollview
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I have an Activity
below:
<RecyclerView> // with horizontal LinearLayoutManager and PagerSnapHelper
<RecyclerView> // with vertical LinearLayoutManager
<RecyclcerView /> // with horizontal LinearLayoutManager
<HorizontalScrollView />
// ... and there are other normal list items
</RecyclerView>
<RecyclerView> // another RV with vertical LinearLayoutManager
</RecyclerView>
</RecyclerView>
The problem is when I scroll horizontally, the inner horizontal RecyclerView
and HorizontalScrollView
doesn't scroll as expected.
Why I have to do this:
I have several ListFragment
s, each of which takes data from different data sources, but has same type of list items. I don't want a ViewPager
, which either hold all pages immediately after ViewPager
is created(which may cause OutOfMemoryError), or reload data from network after user scrolling to other pages and scroll back. Further more, with nested RV, pages can share one same RecyclerViewPool
, which helps to decrease total count of item views in all pages.
What I have done in the outer horizontal RV:
private static final int INVALID_POINTER = -1;
private int mActivePointerId = INVALID_POINTER;
private float lastX;
private GestureDetector mVerticalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) < Math.abs(distanceY);
}
});
private GestureDetector mHorizontalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) > Math.abs(distanceY);
}
});
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if (mVerticalScrollGestureDetector.onTouchEvent(e) || !mAllowPageScroll) {
return false;
}
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = e.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
int pointerIndex = e.findPointerIndex(mActivePointerId);
float x = e.getX(pointerIndex);
float dx = x - lastX;
lastX = x;
if (childCanScroll(this, false, (int) dx, (int) x)) {
Log.d("ScrollX", "not intercept");
return false;
}
Log.d("ScrollX", "maybe intercept");
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mActivePointerId = INVALID_POINTER;
break;
}
return super.onInterceptTouchEvent(e);
}
private boolean childCanScroll(View v, boolean considerSelf, int dx, int x) {
if (v instanceof ViewGroup) {
ViewGroup group = (ViewGroup) v;
int scrollX = v.getScrollX();
for (int i = group.getChildCount() - 1; i >= 0; i--) {
View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
&& childCanScroll(child, true, dx, x + scrollX - child.getLeft())) {
return true;
}
}
}
return considerSelf && v.canScrollHorizontally(-dx);
}
Now it works with inner horizontal RV with occasionally not scrolling, and doesn't work with HorizontalScrollView
at all.
How can I achieve the goal to make inner horizontally-scrollable view to scroll first?
android-recyclerview android-nestedscrollview
I have an Activity
below:
<RecyclerView> // with horizontal LinearLayoutManager and PagerSnapHelper
<RecyclerView> // with vertical LinearLayoutManager
<RecyclcerView /> // with horizontal LinearLayoutManager
<HorizontalScrollView />
// ... and there are other normal list items
</RecyclerView>
<RecyclerView> // another RV with vertical LinearLayoutManager
</RecyclerView>
</RecyclerView>
The problem is when I scroll horizontally, the inner horizontal RecyclerView
and HorizontalScrollView
doesn't scroll as expected.
Why I have to do this:
I have several ListFragment
s, each of which takes data from different data sources, but has same type of list items. I don't want a ViewPager
, which either hold all pages immediately after ViewPager
is created(which may cause OutOfMemoryError), or reload data from network after user scrolling to other pages and scroll back. Further more, with nested RV, pages can share one same RecyclerViewPool
, which helps to decrease total count of item views in all pages.
What I have done in the outer horizontal RV:
private static final int INVALID_POINTER = -1;
private int mActivePointerId = INVALID_POINTER;
private float lastX;
private GestureDetector mVerticalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) < Math.abs(distanceY);
}
});
private GestureDetector mHorizontalScrollGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return Math.abs(distanceX) > Math.abs(distanceY);
}
});
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if (mVerticalScrollGestureDetector.onTouchEvent(e) || !mAllowPageScroll) {
return false;
}
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = e.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
int pointerIndex = e.findPointerIndex(mActivePointerId);
float x = e.getX(pointerIndex);
float dx = x - lastX;
lastX = x;
if (childCanScroll(this, false, (int) dx, (int) x)) {
Log.d("ScrollX", "not intercept");
return false;
}
Log.d("ScrollX", "maybe intercept");
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mActivePointerId = INVALID_POINTER;
break;
}
return super.onInterceptTouchEvent(e);
}
private boolean childCanScroll(View v, boolean considerSelf, int dx, int x) {
if (v instanceof ViewGroup) {
ViewGroup group = (ViewGroup) v;
int scrollX = v.getScrollX();
for (int i = group.getChildCount() - 1; i >= 0; i--) {
View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight()
&& childCanScroll(child, true, dx, x + scrollX - child.getLeft())) {
return true;
}
}
}
return considerSelf && v.canScrollHorizontally(-dx);
}
Now it works with inner horizontal RV with occasionally not scrolling, and doesn't work with HorizontalScrollView
at all.
How can I achieve the goal to make inner horizontally-scrollable view to scroll first?
android-recyclerview android-nestedscrollview
android-recyclerview android-nestedscrollview
edited Nov 7 at 9:12
asked Nov 7 at 5:01
HJWAJ
435
435
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
accepted
There are two mistakes I make.
In case of
ACTION_DOWN
I need to record thelastX
variable as well as in case ofACTION_MOVE
, so that first move ofdx
is a proper value. This explains why thechildCanScroll
method doesn't work on things likeScrollView
(asRecyclerView
'sgetScrollX()
always return 0).In method
childCanScroll
, the innerif
statement should not only consider the x coordinate, but also the y coordinate. If y is not considered, when I scroll outside inner horizontal-scrollable-views, the method also returntrue
, that make things not working properly.
After I fix these two mistakes all things are right.
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
accepted
There are two mistakes I make.
In case of
ACTION_DOWN
I need to record thelastX
variable as well as in case ofACTION_MOVE
, so that first move ofdx
is a proper value. This explains why thechildCanScroll
method doesn't work on things likeScrollView
(asRecyclerView
'sgetScrollX()
always return 0).In method
childCanScroll
, the innerif
statement should not only consider the x coordinate, but also the y coordinate. If y is not considered, when I scroll outside inner horizontal-scrollable-views, the method also returntrue
, that make things not working properly.
After I fix these two mistakes all things are right.
add a comment |
up vote
0
down vote
accepted
There are two mistakes I make.
In case of
ACTION_DOWN
I need to record thelastX
variable as well as in case ofACTION_MOVE
, so that first move ofdx
is a proper value. This explains why thechildCanScroll
method doesn't work on things likeScrollView
(asRecyclerView
'sgetScrollX()
always return 0).In method
childCanScroll
, the innerif
statement should not only consider the x coordinate, but also the y coordinate. If y is not considered, when I scroll outside inner horizontal-scrollable-views, the method also returntrue
, that make things not working properly.
After I fix these two mistakes all things are right.
add a comment |
up vote
0
down vote
accepted
up vote
0
down vote
accepted
There are two mistakes I make.
In case of
ACTION_DOWN
I need to record thelastX
variable as well as in case ofACTION_MOVE
, so that first move ofdx
is a proper value. This explains why thechildCanScroll
method doesn't work on things likeScrollView
(asRecyclerView
'sgetScrollX()
always return 0).In method
childCanScroll
, the innerif
statement should not only consider the x coordinate, but also the y coordinate. If y is not considered, when I scroll outside inner horizontal-scrollable-views, the method also returntrue
, that make things not working properly.
After I fix these two mistakes all things are right.
There are two mistakes I make.
In case of
ACTION_DOWN
I need to record thelastX
variable as well as in case ofACTION_MOVE
, so that first move ofdx
is a proper value. This explains why thechildCanScroll
method doesn't work on things likeScrollView
(asRecyclerView
'sgetScrollX()
always return 0).In method
childCanScroll
, the innerif
statement should not only consider the x coordinate, but also the y coordinate. If y is not considered, when I scroll outside inner horizontal-scrollable-views, the method also returntrue
, that make things not working properly.
After I fix these two mistakes all things are right.
answered 2 days ago
HJWAJ
435
435
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53183810%2fhorizontal-scrollview-inside-vertical-recyclerview-inside-horizontal-recyclervie%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown