ListView in BottomSheet

I ran into a problem when I had a simple ListView in BottomSheet and the ListView had enough elements to fill the screen and scroll even more.

When I scroll down, everything works, however, when I tried to scroll back, it scrolled through the BottomSheet itself and closed the view, rather than just scrolling through the ListView .

I managed to find a solution after a while, and since I could not find it here, I decided that I posted it here.

+14
source share
6 answers

The solution is to extend the ListView as follows:

 public class BottomSheetListView extends ListView { public BottomSheetListView (Context context, AttributeSet p_attrs) { super (context, p_attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true; } @Override public boolean onTouchEvent(MotionEvent ev) { if (canScrollVertically(this)) { getParent().requestDisallowInterceptTouchEvent(true); } return super.onTouchEvent(ev); } public boolean canScrollVertically (AbsListView view) { boolean canScroll = false; if (view !=null && view.getChildCount ()> 0) { boolean isOnTop = view.getFirstVisiblePosition() != 0 || view.getChildAt(0).getTop() != 0; boolean isAllItemsVisible = isOnTop && view.getLastVisiblePosition() == view.getChildCount(); if (isOnTop || isAllItemsVisible) { canScroll = true; } } return canScroll; } } 

Then in your layout file bottom_sheet_view.xml :

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <com.mypackage.name.BottomSheetListView android:id="@+id/listViewBtmSheet" android:divider="@color/colorPrimary" android:dividerHeight="1dp" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" /> </LinearLayout> 

Then finally in Activity / Fragment :

 BottomSheetDialog dialog = new BottomSheetDialog(context); dialog.setContentView(R.layout.bottom_sheet_view); BottomSheetListView listView = (BottomSheetListView) dialog.findViewById(R.id.listViewBtmSheet); // apply some adapter - add some data to listview dialog.show(); 

This will provide a BottomSheet that works fully with ListView scrolling.

+27
source

There is a better approach if you do not want to extend the ListView :

 //in onCreate _listView.setOnTouchListener(new ListView.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // Disallow NestedScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: // Allow NestedScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(false); break; } // Handle ListView touch events. v.onTouchEvent(event); return true; } }); 
+7
source

This is the correct custom touch event list view class.

 public class BottomSheetListView extends ListView { public BottomSheetListView(Context context, AttributeSet p_attrs) { super(context, p_attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (canScrollVertically(this)) { getParent().requestDisallowInterceptTouchEvent(true); } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { if (canScrollVertically(this)) { getParent().requestDisallowInterceptTouchEvent(true); } return super.onTouchEvent(ev); } public boolean canScrollVertically(AbsListView view) { boolean canScroll = false; if (view != null && view.getChildCount() > 0) { boolean isOnTop = view.getFirstVisiblePosition() != 0 || view.getChildAt(0).getTop() != 0; boolean isAllItemsVisible = isOnTop && view.getLastVisiblePosition() == view.getChildCount(); if (isOnTop || isAllItemsVisible) { canScroll = true; } } return canScroll; } } 
+4
source
 public class BottomSheetListView extends ListView { public BottomSheetListView(Context context, AttributeSet attributeSet) { super(context, attributeSet); } @Override public boolean onInterceptTouchEvent(MotionEvent motionEvent) { View view = (View) getChildAt(getChildCount() - 1); int diffBottom = (view.getBottom() - (getHeight() + getScrollY())); if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { if (diffBottom == 0) { return false; } } /*//Need more improvement on this logic. Do not uncomment int diffTop = (view.getTop() - (getHeight() + getScrollY())); if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { if (diffTop < 0) { return true; } }*/ return super.onInterceptTouchEvent(motionEvent); } @Override public boolean onTouchEvent(MotionEvent motionEvent) { if (canScrollVertically(this)) { getParent().requestDisallowInterceptTouchEvent(true); } return super.onTouchEvent(motionEvent); } public boolean canScrollVertically(AbsListView absListView) { boolean canScroll = false; if (absListView != null && absListView.getChildCount() > 0) { boolean isOnTop = absListView.getFirstVisiblePosition() != 0 || absListView.getChildAt(0).getTop() != 0; boolean isAllItemsVisible = isOnTop && getLastVisiblePosition() == absListView.getChildCount(); if (isOnTop || isAllItemsVisible) canScroll = true; } return canScroll; } } 
+3
source

I know this is a bit of a hack, but it worked for me, and even a listview can be selected. As we know, when ever the bottom sheet changes its state, it can be caught in this listener, so do not let it change state if the listview does not touch the top, henceforth the touch event will be passed to the listview and will work as it is.

  mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback(){ @Override public void onStateChanged(View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_DRAGGING && !listIsAtTop()){ mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); } } @Override public void onSlide(View bottomSheet, float slideOffset) {}}); public boolean listIsAtTop() { if(tripListView.getChildCount() == 0) return true; return (tripListView.getChildAt(0).getTop() == 0 && tripListView.getFirstVisiblePosition() ==0); } 
0
source

Starting with version 22.1.0, you can try setNestedScrollingEnabled=true

If this property is set to true, the view will be allowed to initiate nested scroll operations with a compatible parent view in the current hierarchy. If this view does not implement nested scrolling, it will have no effect. Disabling nested scrolling while performing nested scrolling stops nested scrolling.

Google API Link

0
source

Source: https://habr.com/ru/post/1012273/


All Articles