I have a SlidingUpPanelLayout that holds a image as a top view, and a view pager that needs to slide.
The viewpager
has 3 fragments and two of them are list views. So I want to be able to expand the view pager on pulling up, and once the view pager is up I want to be able to scroll the scrollviews
inside the fragments. But when pulling down on the scrollview
in case there is no more to scroll, I want to start collapsing the viewpager
.
So please suggest how to make the SlidingUpPanelLayout
collapse on pulling the scrollview in case there is no more contents to scroll?
Here I post some of my code:
I have tried capture the touch events and overwrite the SlidingUpPanel onInterceptTouchEvent
function in the following way:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isHandled) {
Log.i("interceptToch", "HEREEE");
return onTouchEvent(ev);
}
return false;
}
So when the SlidingUpPanelLayout is expanded I set isHandled = false
. So when the slidingUpPanelLayout expands, all touch events are passed to its child views.
And I also put onTouchEvent
in the scrollView
, in-order to unblock the SlidingUpPanelLayout.onInterceptTouchEvent
:
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
scroll = 0;
y = event.getY();
} else if (action == MotionEvent.ACTION_MOVE) {
if (scroll_view_summary.getScrollY() == 0 && event.getY() > y) {
scroll = scroll + 1;
if (scroll > 2) {
// the user has pulled the list and the slidingUpPanelLauout
// should be able to handle the toch events again
SlidingUpPanelLayoutCustom las =
((SaleDetailsActivity) getActivity()).getLayout();
las.setHandle(true);
scroll = 0;
return false;
}
}
}
return false;
}
But this is not working. The problem is that once the scrollview.onTouch
event is in MotionEvent.ACTION_MOVE
SlidingUpPanelLayout.onInterceptTouchEvent
is not called. SlidingUpPanelLayout.onInterceptTouchEvent
is called after MotionEvent.ACTION_CANCEL
. This means that the event can't be passed to the SlidingUpPanelLayout and the panel can't collapse.
Since 3.1.0, Umano SlidingUpPanelLayout support nested scrolling with ScrollView, ListView and RecyclerView out of the box.
In most of the cases, simply add the
sothree:umanoScrollableView
attribute in your XML layout file, as following :For further information, look at this link : https://github.com/umano/AndroidSlidingUpPanel#scrollable-sliding-views
Unfortunately you can't rely on SlidingUpPanelLayout's
onInterceptTouchEvent
method for the aforementioned reasons. Once a child view'sonTouchEvent
method returnstrue
,onInterceptTouchEvent
is no longer called.My solution is a bit convoluted, but it allows you to achieve exactly what (I think) you're looking for. A single touch/drag event will drag the panel into place and, once in place, continue scrolling the child view. Likewise when dragging down, a single touch/drag event can scroll the child view and, once completely scrolled, will begin dragging the panel down.
Updated 2015-04-12 Updated to version 3.0.0 of the SlidingUpPanelLayout code. Also accounting for ListViews instead of just ScrollViews.
1) In the
res/
folder of SlidingUpPanel's library project, open theattrs.xml
and addYou'll use this to identify a single child view that will usurp the touch event once the panel has been dragged into position. In your layout xml file, you can then add
Or whatever the ID of your scrollView is. Also make sure that you do not declare a
sothree:dragView
ID, so the entire view is draggable.The rest of the steps are all done within
SlidingUpPanelLayout.java
...2) Declare the following variables:
3) In the constructor, just after
mDragViewResId
is set, add the following line:4) In
onFinishInflate
, add the following code:5) Add the following method:
6) Remove
onInterceptTouchEvent
.7) Modify
onTouchEvent
to the following:8) Add the following method:
9) Add the following method to determine whether the scrollView is still scrolling. Handles cases for both ScrollView and ListView:
10) (Optional) Add the following method to allow you to set the scrollView at runtime (i.e. You want to put a fragment in the panel, and the fragment's child has a ScrollView/ListView you want to scroll):
We're now completely managing the handling of the touch event from within this class. If we're dragging the panel up and it slides fully into place, we cancel the drag and then spoof a new touch in the
mScrollView
child. If we're scrolling the child and reach the top, we spoof an "up" event in the child and spoof a new touch for the drag. This also allows tap events on other child widgets.Known Issues The "up"/"down" events that we're spoofing can unintentionally trigger a click event on a child element of the scrollView.
In order for JJD's answer to work you need to add another step
8) add this method
mScrollViewResId = ta.getResourceId(R.styleable.SlidingUpPanelLayout_scrollView, -1);
in the constructor of the SlidingPanelLayoutJust use
setScrollableView
!Example:
Scrollable view can be is
RecyclerView
,ListView
,ScrollView
etc.Wow! 4 years have passed! But the question is still relevant. At least for me. I found a solution in a small section of the code and without modifying the library. It works fine with ScrollView.
usage:
I had the same issue but at my app there is ListView instead of ScrollView. I couldn't apply themarshal's answer to work for my problem. But I have found solution on the basis of themarshal's, Chris's answers and Maria Sakharova's comments
First I couldn't find variables mCanSlide and mIsSlidingEnabled and methods expandPane(mAnchorPoint) and collapsePane() so I use next code:
try/catch is needed because of exception raises when apply two fingers.
Second Chris's answers is obligatory to fulfill.
And then because of ListView's method getScrollY() always returns zero I change slightly code at method dispatchTouchEvent(MotionEvent ev):
this:
to:
Also my app has Google Map as main content and it also must get MotionEvent so as Maria Sakharova said we must return this.onTouchEvent(ev) || super.dispatchTouchEvent(ev) instead of this.onTouchEvent(ev) at two places. We must change this code:
to:
in this case super.dispatchTouchEvent(ev) is needed if main content must get MotionEvent.
And second code:
to:
in this case super.dispatchTouchEvent(ev) is needed to able to expand panel.
In summary method dispatchTouchEvent(MotionEvent ev) will be the next: