@@ -178,6 +178,8 @@ public abstract static class BottomSheetCallback {
178178
179179 @ SaveFlags private int saveFlags = SAVE_NONE ;
180180
181+ private static final int SIGNIFICANT_VEL_THRESHOLD = 500 ;
182+
181183 private static final float HIDE_THRESHOLD = 0.5f ;
182184
183185 private static final float HIDE_FRICTION = 0.1f ;
@@ -1025,13 +1027,15 @@ private void updateDrawableForTargetState(@State int state) {
10251027 }
10261028 }
10271029
1028- private void calculateCollapsedOffset () {
1029- int peek ;
1030+ private int calculatePeekHeight () {
10301031 if (peekHeightAuto ) {
1031- peek = Math .max (peekHeightMin , parentHeight - parentWidth * 9 / 16 );
1032- } else {
1033- peek = peekHeight ;
1032+ return Math .max (peekHeightMin , parentHeight - parentWidth * 9 / 16 );
10341033 }
1034+ return peekHeight ;
1035+ }
1036+
1037+ private void calculateCollapsedOffset () {
1038+ int peek = calculatePeekHeight ();
10351039
10361040 if (fitToContents ) {
10371041 collapsedOffset = Math .max (parentHeight - peek , fitToContentsOffset );
@@ -1080,8 +1084,9 @@ boolean shouldHide(@NonNull View child, float yvel) {
10801084 // It should not hide, but collapse.
10811085 return false ;
10821086 }
1087+ int peek = calculatePeekHeight ();
10831088 final float newTop = child .getTop () + yvel * HIDE_FRICTION ;
1084- return Math .abs (newTop - collapsedOffset ) / (float ) peekHeight > HIDE_THRESHOLD ;
1089+ return Math .abs (newTop - collapsedOffset ) / (float ) peek > HIDE_THRESHOLD ;
10851090 }
10861091
10871092 @ Nullable
@@ -1228,6 +1233,11 @@ public void onViewDragStateChanged(int state) {
12281233 }
12291234 }
12301235
1236+ private boolean releasedLow (@ NonNull View child ) {
1237+ // Needs to be at least half way to the bottom.
1238+ return child .getTop () > (parentHeight + getExpandedOffset ()) / 2 ;
1239+ }
1240+
12311241 @ Override
12321242 public void onViewReleased (@ NonNull View releasedChild , float xvel , float yvel ) {
12331243 int top ;
@@ -1246,13 +1256,24 @@ public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel)
12461256 targetState = STATE_EXPANDED ;
12471257 }
12481258 }
1249- } else if (hideable
1250- && shouldHide (releasedChild , yvel )
1251- && (releasedChild .getTop () > collapsedOffset || Math .abs (xvel ) < Math .abs (yvel ))) {
1252- // Hide if we shouldn't collapse and the view was either released low or it was a
1253- // vertical swipe.
1254- top = parentHeight ;
1255- targetState = STATE_HIDDEN ;
1259+ } else if (hideable && shouldHide (releasedChild , yvel )) {
1260+ // Hide if the view was either released low or it was a significant vertical swipe
1261+ // otherwise settle to closest expanded state.
1262+ if ((Math .abs (xvel ) < Math .abs (yvel ) && yvel > SIGNIFICANT_VEL_THRESHOLD )
1263+ || releasedLow (releasedChild )) {
1264+ top = parentHeight ;
1265+ targetState = STATE_HIDDEN ;
1266+ } else if (fitToContents ) {
1267+ top = fitToContentsOffset ;
1268+ targetState = STATE_EXPANDED ;
1269+ } else if (Math .abs (releasedChild .getTop () - expandedOffset )
1270+ < Math .abs (releasedChild .getTop () - halfExpandedOffset )) {
1271+ top = expandedOffset ;
1272+ targetState = STATE_EXPANDED ;
1273+ } else {
1274+ top = halfExpandedOffset ;
1275+ targetState = STATE_HALF_EXPANDED ;
1276+ }
12561277 } else if (yvel == 0.f || Math .abs (xvel ) > Math .abs (yvel )) {
12571278 // If the Y velocity is 0 or the swipe was mostly horizontal indicated by the X velocity
12581279 // being greater than the Y velocity, settle to the nearest correct height.
@@ -1331,7 +1352,7 @@ void dispatchOnSlide(int top) {
13311352 View bottomSheet = viewRef .get ();
13321353 if (bottomSheet != null && !callbacks .isEmpty ()) {
13331354 float slideOffset =
1334- (top > collapsedOffset )
1355+ (top > collapsedOffset || collapsedOffset == getExpandedOffset () )
13351356 ? (float ) (collapsedOffset - top ) / (parentHeight - collapsedOffset )
13361357 : (float ) (collapsedOffset - top ) / (collapsedOffset - getExpandedOffset ());
13371358 for (int i = 0 ; i < callbacks .size (); i ++) {
0 commit comments