@@ -1526,11 +1526,10 @@ public void onAnimationUpdate(@NonNull ValueAnimator animator) {
15261526 }
15271527
15281528 private int getChildIndexOnOffset (@ NonNull T abl , final int offset ) {
1529- final int ablTopInset = abl .getTopInset () + abl .getPaddingTop ();
15301529 for (int i = 0 , count = abl .getChildCount (); i < count ; i ++) {
15311530 View child = abl .getChildAt (i );
1532- int top = child .getTop () - ablTopInset ;
1533- int bottom = child .getBottom () - ablTopInset ;
1531+ int top = child .getTop ();
1532+ int bottom = child .getBottom ();
15341533
15351534 final LayoutParams lp = (LayoutParams ) child .getLayoutParams ();
15361535 if (checkFlag (lp .getScrollFlags (), LayoutParams .SCROLL_FLAG_SNAP_MARGINS )) {
@@ -1547,18 +1546,29 @@ private int getChildIndexOnOffset(@NonNull T abl, final int offset) {
15471546 }
15481547
15491548 private void snapToChildIfNeeded (CoordinatorLayout coordinatorLayout , @ NonNull T abl ) {
1550- final int offset = getTopBottomOffsetForScrollingSibling ();
1549+ final int topInset = abl .getTopInset () + abl .getPaddingTop ();
1550+ // The "baseline" of scrolling is the top of the first child. We "add" insets and paddings
1551+ // to the scrolling amount to align offsets and views with the same y-coordinate. (The origin
1552+ // is at the top of the AppBarLayout, so all the coordinates are with negative values.)
1553+ final int offset = getTopBottomOffsetForScrollingSibling () - topInset ;
15511554 final int offsetChildIndex = getChildIndexOnOffset (abl , offset );
15521555 if (offsetChildIndex >= 0 ) {
15531556 final View offsetChild = abl .getChildAt (offsetChildIndex );
15541557 final LayoutParams lp = (LayoutParams ) offsetChild .getLayoutParams ();
15551558 final int flags = lp .getScrollFlags ();
1556- final int ablTopInset = abl .getTopInset () + abl .getPaddingTop ();
15571559
15581560 if ((flags & LayoutParams .FLAG_SNAP ) == LayoutParams .FLAG_SNAP ) {
15591561 // We're set the snap, so animate the offset to the nearest edge
1560- int snapTop = -offsetChild .getTop () + ablTopInset ;
1561- int snapBottom = -offsetChild .getBottom () + ablTopInset ;
1562+ int snapTop = -offsetChild .getTop ();
1563+ int snapBottom = -offsetChild .getBottom ();
1564+
1565+ // If the child is set to fit system windows, its top will include the inset area, we need
1566+ // to minus the inset from snapTop to make the calculation consistent.
1567+ if (offsetChildIndex == 0
1568+ && ViewCompat .getFitsSystemWindows (abl )
1569+ && ViewCompat .getFitsSystemWindows (offsetChild )) {
1570+ snapTop -= abl .getTopInset ();
1571+ }
15621572
15631573 if (checkFlag (flags , LayoutParams .SCROLL_FLAG_EXIT_UNTIL_COLLAPSED )) {
15641574 // If the view is set only exit until it is collapsed, we'll abide by that
@@ -1581,13 +1591,19 @@ private void snapToChildIfNeeded(CoordinatorLayout coordinatorLayout, @NonNull T
15811591 snapBottom -= lp .bottomMargin ;
15821592 }
15831593
1584- final int newOffset = offset < (snapBottom + snapTop ) / 2 ? snapBottom : snapTop ;
1594+ // Excludes insets and paddings from the offset. (Offsets use the top of child views as
1595+ // the origin.)
1596+ final int newOffset = calculateSnapOffset (offset , snapBottom , snapTop ) + topInset ;
15851597 animateOffsetTo (
15861598 coordinatorLayout , abl , clamp (newOffset , -abl .getTotalScrollRange (), 0 ), 0 );
15871599 }
15881600 }
15891601 }
15901602
1603+ private int calculateSnapOffset (int value , int bottom , int top ) {
1604+ return value < (bottom + top ) / 2 ? bottom : top ;
1605+ }
1606+
15911607 private static boolean checkFlag (final int flags , final int check ) {
15921608 return (flags & check ) == check ;
15931609 }
0 commit comments