46
46
import android .view .ViewGroup ;
47
47
import android .view .ViewOutlineProvider ;
48
48
import android .view .animation .Interpolator ;
49
- import android .widget .AbsListView ;
50
49
import android .widget .LinearLayout ;
51
50
import android .widget .ScrollView ;
52
51
import androidx .annotation .ColorInt ;
63
62
import androidx .core .graphics .drawable .DrawableCompat ;
64
63
import androidx .core .util .ObjectsCompat ;
65
64
import androidx .core .view .AccessibilityDelegateCompat ;
66
- import androidx .core .view .NestedScrollingChild ;
67
65
import androidx .core .view .ViewCompat ;
68
66
import androidx .core .view .ViewCompat .NestedScrollType ;
69
67
import androidx .core .view .WindowInsetsCompat ;
@@ -207,7 +205,7 @@ public interface LiftOnScrollListener {
207
205
208
206
private boolean liftOnScroll ;
209
207
@ IdRes private int liftOnScrollTargetViewId ;
210
- @ Nullable private WeakReference <View > liftOnScrollTargetView ;
208
+ @ Nullable private WeakReference <View > liftOnScrollTargetViewRef ;
211
209
private final boolean hasLiftOnScrollColor ;
212
210
@ Nullable private ValueAnimator liftOnScrollColorAnimator ;
213
211
@ Nullable private AnimatorUpdateListener liftOnScrollColorUpdateListener ;
@@ -761,7 +759,7 @@ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
761
759
protected void onDetachedFromWindow () {
762
760
super .onDetachedFromWindow ();
763
761
764
- clearLiftOnScrollTargetView ();
762
+ clearLiftOnScrollTargetViewRef ();
765
763
}
766
764
767
765
boolean hasChildWithInterpolator () {
@@ -1087,9 +1085,9 @@ public boolean isLiftOnScroll() {
1087
1085
public void setLiftOnScrollTargetView (@ Nullable View liftOnScrollTargetView ) {
1088
1086
this .liftOnScrollTargetViewId = View .NO_ID ;
1089
1087
if (liftOnScrollTargetView == null ) {
1090
- clearLiftOnScrollTargetView ();
1088
+ clearLiftOnScrollTargetViewRef ();
1091
1089
} else {
1092
- this .liftOnScrollTargetView = new WeakReference <>(liftOnScrollTargetView );
1090
+ this .liftOnScrollTargetViewRef = new WeakReference <>(liftOnScrollTargetView );
1093
1091
}
1094
1092
}
1095
1093
@@ -1100,7 +1098,7 @@ public void setLiftOnScrollTargetView(@Nullable View liftOnScrollTargetView) {
1100
1098
public void setLiftOnScrollTargetViewId (@ IdRes int liftOnScrollTargetViewId ) {
1101
1099
this .liftOnScrollTargetViewId = liftOnScrollTargetViewId ;
1102
1100
// Invalidate cached target view so it will be looked up on next scroll.
1103
- clearLiftOnScrollTargetView ();
1101
+ clearLiftOnScrollTargetViewRef ();
1104
1102
}
1105
1103
1106
1104
/**
@@ -1112,39 +1110,58 @@ public int getLiftOnScrollTargetViewId() {
1112
1110
return liftOnScrollTargetViewId ;
1113
1111
}
1114
1112
1115
- boolean shouldLift (@ Nullable View defaultScrollingView ) {
1116
- View scrollingView = findLiftOnScrollTargetView (defaultScrollingView );
1117
- if (scrollingView == null ) {
1118
- scrollingView = defaultScrollingView ;
1119
- }
1113
+ boolean shouldBeLifted () {
1114
+ final View scrollingView = findLiftOnScrollTargetView ();
1120
1115
return scrollingView != null
1121
1116
&& (scrollingView .canScrollVertically (-1 ) || scrollingView .getScrollY () > 0 );
1122
1117
}
1123
1118
1124
1119
@ Nullable
1125
- private View findLiftOnScrollTargetView (@ Nullable View defaultScrollingView ) {
1120
+ private View findLiftOnScrollTargetView () {
1121
+ View liftOnScrollTargetView = liftOnScrollTargetViewRef != null
1122
+ ? liftOnScrollTargetViewRef .get ()
1123
+ : null ;
1124
+
1125
+ final ViewGroup parent = (ViewGroup ) getParent ();
1126
+
1126
1127
if (liftOnScrollTargetView == null && liftOnScrollTargetViewId != View .NO_ID ) {
1127
- View targetView = null ;
1128
- if (defaultScrollingView != null ) {
1129
- targetView = defaultScrollingView .findViewById (liftOnScrollTargetViewId );
1130
- }
1131
- if (targetView == null && getParent () instanceof ViewGroup ) {
1132
- // Assumes the scrolling view is a child of the AppBarLayout's parent,
1133
- // which should be true due to the CoordinatorLayout pattern.
1134
- targetView = ((ViewGroup ) getParent ()).findViewById (liftOnScrollTargetViewId );
1128
+ liftOnScrollTargetView = parent .findViewById (liftOnScrollTargetViewId );
1129
+ if (liftOnScrollTargetView != null ) {
1130
+ clearLiftOnScrollTargetViewRef ();
1131
+ liftOnScrollTargetViewRef = new WeakReference <>(liftOnScrollTargetView );
1135
1132
}
1136
- if (targetView != null ) {
1137
- liftOnScrollTargetView = new WeakReference <>(targetView );
1133
+ }
1134
+
1135
+ return liftOnScrollTargetView != null
1136
+ ? liftOnScrollTargetView
1137
+ : findFirstChildWithScrollingBehavior (parent );
1138
+ }
1139
+
1140
+ @ Nullable
1141
+ private View findFirstChildWithScrollingBehavior (@ NonNull ViewGroup parent ) {
1142
+ for (int i = 0 , z = parent .getChildCount (); i < z ; i ++) {
1143
+ final View child = parent .getChildAt (i );
1144
+ if (hasScrollingBehavior (child )) {
1145
+ return child ;
1138
1146
}
1139
1147
}
1140
- return liftOnScrollTargetView != null ? liftOnScrollTargetView . get () : null ;
1148
+ return null ;
1141
1149
}
1142
1150
1143
- private void clearLiftOnScrollTargetView () {
1144
- if (liftOnScrollTargetView != null ) {
1145
- liftOnScrollTargetView .clear ();
1151
+ private boolean hasScrollingBehavior (@ NonNull View view ) {
1152
+ if (view .getLayoutParams () instanceof CoordinatorLayout .LayoutParams ) {
1153
+ CoordinatorLayout .LayoutParams lp = (CoordinatorLayout .LayoutParams ) view .getLayoutParams ();
1154
+ return lp .getBehavior () instanceof ScrollingViewBehavior ;
1146
1155
}
1147
- liftOnScrollTargetView = null ;
1156
+
1157
+ return false ;
1158
+ }
1159
+
1160
+ private void clearLiftOnScrollTargetViewRef () {
1161
+ if (liftOnScrollTargetViewRef != null ) {
1162
+ liftOnScrollTargetViewRef .clear ();
1163
+ }
1164
+ liftOnScrollTargetViewRef = null ;
1148
1165
}
1149
1166
1150
1167
/**
@@ -1561,12 +1578,12 @@ private boolean canScrollChildren(
1561
1578
1562
1579
@ Override
1563
1580
public void onNestedPreScroll (
1564
- CoordinatorLayout coordinatorLayout ,
1581
+ @ NonNull CoordinatorLayout coordinatorLayout ,
1565
1582
@ NonNull T child ,
1566
- View target ,
1583
+ @ NonNull View target ,
1567
1584
int dx ,
1568
1585
int dy ,
1569
- int [] consumed ,
1586
+ @ NonNull int [] consumed ,
1570
1587
int type ) {
1571
1588
if (dy != 0 ) {
1572
1589
int min ;
@@ -1585,7 +1602,7 @@ public void onNestedPreScroll(
1585
1602
}
1586
1603
}
1587
1604
if (child .isLiftOnScroll ()) {
1588
- child .setLiftedState (child .shouldLift ( target ));
1605
+ child .setLiftedState (child .shouldBeLifted ( ));
1589
1606
}
1590
1607
}
1591
1608
@@ -1616,7 +1633,10 @@ public void onNestedScroll(
1616
1633
1617
1634
@ Override
1618
1635
public void onStopNestedScroll (
1619
- CoordinatorLayout coordinatorLayout , @ NonNull T abl , View target , int type ) {
1636
+ @ NonNull CoordinatorLayout coordinatorLayout ,
1637
+ @ NonNull T abl ,
1638
+ @ NonNull View target ,
1639
+ int type ) {
1620
1640
// onStartNestedScroll for a fling will happen before onStopNestedScroll for the scroll. This
1621
1641
// isn't necessarily guaranteed yet, but it should be in the future. We use this to our
1622
1642
// advantage to check if a fling (ViewCompat.TYPE_NON_TOUCH) will start after the touch scroll
@@ -1625,7 +1645,7 @@ public void onStopNestedScroll(
1625
1645
// If we haven't been flung, or a fling is ending
1626
1646
snapToChildIfNeeded (coordinatorLayout , abl );
1627
1647
if (abl .isLiftOnScroll ()) {
1628
- abl .setLiftedState (abl .shouldLift ( target ));
1648
+ abl .setLiftedState (abl .shouldBeLifted ( ));
1629
1649
}
1630
1650
}
1631
1651
@@ -2034,7 +2054,7 @@ void onFlingFinished(@NonNull CoordinatorLayout parent, @NonNull T layout) {
2034
2054
// At the end of a manual fling, check to see if we need to snap to the edge-child
2035
2055
snapToChildIfNeeded (parent , layout );
2036
2056
if (layout .isLiftOnScroll ()) {
2037
- layout .setLiftedState (layout .shouldLift ( findFirstScrollingChild ( parent ) ));
2057
+ layout .setLiftedState (layout .shouldBeLifted ( ));
2038
2058
}
2039
2059
}
2040
2060
@@ -2201,9 +2221,7 @@ private void updateAppBarLayoutDrawableState(
2201
2221
}
2202
2222
2203
2223
if (layout .isLiftOnScroll ()) {
2204
- // Use first scrolling child as default scrolling view for updating lifted state because
2205
- // it represents the content that would be scrolled beneath the app bar.
2206
- lifted = layout .shouldLift (findFirstScrollingChild (parent ));
2224
+ lifted = layout .shouldBeLifted ();
2207
2225
}
2208
2226
2209
2227
final boolean changed = layout .setLiftedState (lifted );
@@ -2253,19 +2271,6 @@ private static View getAppBarChildOnOffset(
2253
2271
return null ;
2254
2272
}
2255
2273
2256
- @ Nullable
2257
- private View findFirstScrollingChild (@ NonNull CoordinatorLayout parent ) {
2258
- for (int i = 0 , z = parent .getChildCount (); i < z ; i ++) {
2259
- final View child = parent .getChildAt (i );
2260
- if (child instanceof NestedScrollingChild
2261
- || child instanceof AbsListView
2262
- || child instanceof ScrollView ) {
2263
- return child ;
2264
- }
2265
- }
2266
- return null ;
2267
- }
2268
-
2269
2274
@ Override
2270
2275
int getTopBottomOffsetForScrollingSibling () {
2271
2276
return getTopAndBottomOffset () + offsetDelta ;
@@ -2402,7 +2407,7 @@ public boolean layoutDependsOn(CoordinatorLayout parent, View child, View depend
2402
2407
public boolean onDependentViewChanged (
2403
2408
@ NonNull CoordinatorLayout parent , @ NonNull View child , @ NonNull View dependency ) {
2404
2409
offsetChildAsNeeded (child , dependency );
2405
- updateLiftedStateIfNeeded (child , dependency );
2410
+ updateLiftedStateIfNeeded (dependency );
2406
2411
return false ;
2407
2412
}
2408
2413
@@ -2509,11 +2514,11 @@ int getScrollRange(View v) {
2509
2514
}
2510
2515
}
2511
2516
2512
- private void updateLiftedStateIfNeeded (View child , View dependency ) {
2517
+ private void updateLiftedStateIfNeeded (@ NonNull View dependency ) {
2513
2518
if (dependency instanceof AppBarLayout ) {
2514
2519
AppBarLayout appBarLayout = (AppBarLayout ) dependency ;
2515
2520
if (appBarLayout .isLiftOnScroll ()) {
2516
- appBarLayout .setLiftedState (appBarLayout .shouldLift ( child ));
2521
+ appBarLayout .setLiftedState (appBarLayout .shouldBeLifted ( ));
2517
2522
}
2518
2523
}
2519
2524
}
0 commit comments