Pass motion event to parent scroll when Listview top / bottom

I have a ListView in ScrollView to display comments, and I would like to do the following:

When the user bounces, the ScrollView must first scroll down completely, since the list is at the bottom. After it is completely omitted, Listiew should start scrolling.

Similarly, when the user scrolls, the ListView first (the reverse order is here!) Must scroll up before ScrollView starts scrolling.

So far I have done the following:

 listView.setOnTouchListener(new View.OnTouchListener() { // Setting on Touch Listener for handling the touch inside ScrollView @Override public boolean onTouch(View v, MotionEvent event) { // If going up but the list is already at up, return false indicating we did not consume it. if(event.getAction() == MotionEvent.ACTION_UP) { if (listView.getChildCount() == 0 && listView.getChildAt(0).getTop() == 0) { Log.e("Listview", "At top!"); return false; } } // Similar behaviour but when going down check if we are at the bottom. if( event.getAction() == MotionEvent.ACTION_DOWN) { if (listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 && listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) { Log.e("Listview","At bottom!"); v.getParent().requestDisallowInterceptTouchEvent(false); return false; } } v.getParent().requestDisallowInterceptTouchEvent(true); return false; } }); 

ScrollView at the right time, however ScrollView will not move even if I return false.

I also tried adding v.getParent().requestDisallowInterceptTouchEvent(false); to the operators, but that didn't work either.

How can I make it work?

+8
android listview scrollview motionevent
source share
3 answers

You can create custom ScrollView and ListView and override

 onInterceptTouchEvent(MotionEvent event) 

like this:

 @Override public boolean onInterceptTouchEvent(MotionEvent event) { View view = (View) getChildAt(getChildCount()-1); int diff = (view.getBottom()-(getHeight()+getScrollY())); if( event.getAction() == MotionEvent.ACTION_DOWN) { if (diff ==0) { return false; } } return super.onInterceptTouchEvent(event); } 

Thus, each press of the ListView button, when you are at the bottom of the ScrollView , will go to the ListView .

This is just a sketch implementation, but I think you could start by doing the same to detect when you are at the top of the ListView

As a side note, I would try to simplify the implementation using only ListView with the current contents of you ScrollView added as a ListView title using listView.addHeaderView(scrollViewContent) . I don’t know if this fits your needs.

EDIT:

Detecting when to start scrolling ScrollView . Saving a ListView link to a ScrollView . When the user scrolls and the ListView is at the top, let the event be consumed by the ScrollView .

 private void init(){ ViewConfiguration vc = ViewConfiguration.get(getContext()); mTouchSlop = vc.getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { final int action = MotionEventCompat.getActionMasked(event); switch (action) { case MotionEvent.ACTION_DOWN:{ yPrec = event.getY(); } case MotionEvent.ACTION_MOVE: { final float dy = event.getY() - yPrec; if (dy > mTouchSlop) { // Start scrolling! mIsScrolling = true; } break; } } if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { mIsScrolling = false; } // Calculate the scrolldiff View view = (View) getChildAt(getChildCount()-1); int diff = (view.getBottom()-(getHeight()+getScrollY())); if ((!mIsScrolling || !listViewReference.listIsAtTop()) && diff == 0) { if (event.getAction() == MotionEvent.ACTION_MOVE) { return false; } } return super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { mIsScrolling = false; } return super.onTouchEvent(ev); } public void setListViewReference(MyListView listViewReference) { this.listViewReference = listViewReference; } 

The listIsAtTop method in a ListView is as follows:

 public boolean listIsAtTop() { if(getChildCount() == 0) return true; return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0); } 
+8
source share

You cannot put a ListView inside a ScrollView, but you can achieve your requirement using an ExpandableHeightListView . This will make a complete Listview inside ScrollView. No need to add TouchListener.

 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <!-- your content --> </RelativeLayout> <my.widget.ExpandableHeightListView android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </ScrollView> 

And another way to achieve your requirement is a RecyclerView with a title.

+4
source share

Try the following:

  • First find if you reached in scrollview Bottom. Register onScrollChanged in your scroll view

     @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { // Grab the last child placed in the ScrollView, we need it to determinate the bottom position. View view = (View) getChildAt(getChildCount()-1); // Calculate the scrolldiff int diff = (view.getBottom()-(getHeight()+getScrollY())); // if diff is zero, then the bottom has been reached if( diff == 0 ) { // notify that we have reached the bottom // Add code here to start scrolling the ListView Log.d(ScrollTest.LOG_TAG, "MyScrollView: Bottom has been reached" ); } super.onScrollChanged(l, t, oldl, oldt); } 
  • Check if you have reached the top of the ListView. Make sure firstVisibleItem is 0: -

     tableListView.setOnScrollListener(new OnScrollListener() { public void onScrollStateChanged(AbsListView view, int scrollState) { } public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (visibleItemCount == 0) // you have reached at top of lustView { java.lang.System.out.println("you have reached at top of lustView!"); } else { if ((firstVisibleItem + visibleItemCount) == totalItemCount) { // put your stuff here java.lang.System.out.println("end of the line reached!"); } } } }); 

Hope this works for you. If you have any problems, let me know.

0
source share

All Articles