4646import android .view .ViewGroup ;
4747import android .view .ViewOutlineProvider ;
4848import android .view .animation .Interpolator ;
49- import android .widget .AbsListView ;
5049import android .widget .LinearLayout ;
5150import android .widget .ScrollView ;
5251import androidx .annotation .ColorInt ;
6362import androidx .core .graphics .drawable .DrawableCompat ;
6463import androidx .core .util .ObjectsCompat ;
6564import androidx .core .view .AccessibilityDelegateCompat ;
66- import androidx .core .view .NestedScrollingChild ;
6765import androidx .core .view .ViewCompat ;
6866import androidx .core .view .ViewCompat .NestedScrollType ;
6967import androidx .core .view .WindowInsetsCompat ;
@@ -207,7 +205,7 @@ public interface LiftOnScrollListener {
207205
208206 private boolean liftOnScroll ;
209207 @ IdRes private int liftOnScrollTargetViewId ;
210- @ Nullable private WeakReference <View > liftOnScrollTargetView ;
208+ @ Nullable private WeakReference <View > liftOnScrollTargetViewRef ;
211209 private final boolean hasLiftOnScrollColor ;
212210 @ Nullable private ValueAnimator liftOnScrollColorAnimator ;
213211 @ Nullable private AnimatorUpdateListener liftOnScrollColorUpdateListener ;
@@ -761,7 +759,7 @@ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
761759 protected void onDetachedFromWindow () {
762760 super .onDetachedFromWindow ();
763761
764- clearLiftOnScrollTargetView ();
762+ clearLiftOnScrollTargetViewRef ();
765763 }
766764
767765 boolean hasChildWithInterpolator () {
@@ -1087,9 +1085,9 @@ public boolean isLiftOnScroll() {
10871085 public void setLiftOnScrollTargetView (@ Nullable View liftOnScrollTargetView ) {
10881086 this .liftOnScrollTargetViewId = View .NO_ID ;
10891087 if (liftOnScrollTargetView == null ) {
1090- clearLiftOnScrollTargetView ();
1088+ clearLiftOnScrollTargetViewRef ();
10911089 } else {
1092- this .liftOnScrollTargetView = new WeakReference <>(liftOnScrollTargetView );
1090+ this .liftOnScrollTargetViewRef = new WeakReference <>(liftOnScrollTargetView );
10931091 }
10941092 }
10951093
@@ -1100,7 +1098,7 @@ public void setLiftOnScrollTargetView(@Nullable View liftOnScrollTargetView) {
11001098 public void setLiftOnScrollTargetViewId (@ IdRes int liftOnScrollTargetViewId ) {
11011099 this .liftOnScrollTargetViewId = liftOnScrollTargetViewId ;
11021100 // Invalidate cached target view so it will be looked up on next scroll.
1103- clearLiftOnScrollTargetView ();
1101+ clearLiftOnScrollTargetViewRef ();
11041102 }
11051103
11061104 /**
@@ -1112,39 +1110,58 @@ public int getLiftOnScrollTargetViewId() {
11121110 return liftOnScrollTargetViewId ;
11131111 }
11141112
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 ();
11201115 return scrollingView != null
11211116 && (scrollingView .canScrollVertically (-1 ) || scrollingView .getScrollY () > 0 );
11221117 }
11231118
11241119 @ 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+
11261127 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 );
11351132 }
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 ;
11381146 }
11391147 }
1140- return liftOnScrollTargetView != null ? liftOnScrollTargetView . get () : null ;
1148+ return null ;
11411149 }
11421150
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 ;
11461155 }
1147- liftOnScrollTargetView = null ;
1156+
1157+ return false ;
1158+ }
1159+
1160+ private void clearLiftOnScrollTargetViewRef () {
1161+ if (liftOnScrollTargetViewRef != null ) {
1162+ liftOnScrollTargetViewRef .clear ();
1163+ }
1164+ liftOnScrollTargetViewRef = null ;
11481165 }
11491166
11501167 /**
@@ -1561,12 +1578,12 @@ private boolean canScrollChildren(
15611578
15621579 @ Override
15631580 public void onNestedPreScroll (
1564- CoordinatorLayout coordinatorLayout ,
1581+ @ NonNull CoordinatorLayout coordinatorLayout ,
15651582 @ NonNull T child ,
1566- View target ,
1583+ @ NonNull View target ,
15671584 int dx ,
15681585 int dy ,
1569- int [] consumed ,
1586+ @ NonNull int [] consumed ,
15701587 int type ) {
15711588 if (dy != 0 ) {
15721589 int min ;
@@ -1585,7 +1602,7 @@ public void onNestedPreScroll(
15851602 }
15861603 }
15871604 if (child .isLiftOnScroll ()) {
1588- child .setLiftedState (child .shouldLift ( target ));
1605+ child .setLiftedState (child .shouldBeLifted ( ));
15891606 }
15901607 }
15911608
@@ -1616,7 +1633,10 @@ public void onNestedScroll(
16161633
16171634 @ Override
16181635 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 ) {
16201640 // onStartNestedScroll for a fling will happen before onStopNestedScroll for the scroll. This
16211641 // isn't necessarily guaranteed yet, but it should be in the future. We use this to our
16221642 // advantage to check if a fling (ViewCompat.TYPE_NON_TOUCH) will start after the touch scroll
@@ -1625,7 +1645,7 @@ public void onStopNestedScroll(
16251645 // If we haven't been flung, or a fling is ending
16261646 snapToChildIfNeeded (coordinatorLayout , abl );
16271647 if (abl .isLiftOnScroll ()) {
1628- abl .setLiftedState (abl .shouldLift ( target ));
1648+ abl .setLiftedState (abl .shouldBeLifted ( ));
16291649 }
16301650 }
16311651
@@ -2034,7 +2054,7 @@ void onFlingFinished(@NonNull CoordinatorLayout parent, @NonNull T layout) {
20342054 // At the end of a manual fling, check to see if we need to snap to the edge-child
20352055 snapToChildIfNeeded (parent , layout );
20362056 if (layout .isLiftOnScroll ()) {
2037- layout .setLiftedState (layout .shouldLift ( findFirstScrollingChild ( parent ) ));
2057+ layout .setLiftedState (layout .shouldBeLifted ( ));
20382058 }
20392059 }
20402060
@@ -2201,9 +2221,7 @@ private void updateAppBarLayoutDrawableState(
22012221 }
22022222
22032223 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 ();
22072225 }
22082226
22092227 final boolean changed = layout .setLiftedState (lifted );
@@ -2253,19 +2271,6 @@ private static View getAppBarChildOnOffset(
22532271 return null ;
22542272 }
22552273
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-
22692274 @ Override
22702275 int getTopBottomOffsetForScrollingSibling () {
22712276 return getTopAndBottomOffset () + offsetDelta ;
@@ -2402,7 +2407,7 @@ public boolean layoutDependsOn(CoordinatorLayout parent, View child, View depend
24022407 public boolean onDependentViewChanged (
24032408 @ NonNull CoordinatorLayout parent , @ NonNull View child , @ NonNull View dependency ) {
24042409 offsetChildAsNeeded (child , dependency );
2405- updateLiftedStateIfNeeded (child , dependency );
2410+ updateLiftedStateIfNeeded (dependency );
24062411 return false ;
24072412 }
24082413
@@ -2509,11 +2514,11 @@ int getScrollRange(View v) {
25092514 }
25102515 }
25112516
2512- private void updateLiftedStateIfNeeded (View child , View dependency ) {
2517+ private void updateLiftedStateIfNeeded (@ NonNull View dependency ) {
25132518 if (dependency instanceof AppBarLayout ) {
25142519 AppBarLayout appBarLayout = (AppBarLayout ) dependency ;
25152520 if (appBarLayout .isLiftOnScroll ()) {
2516- appBarLayout .setLiftedState (appBarLayout .shouldLift ( child ));
2521+ appBarLayout .setLiftedState (appBarLayout .shouldBeLifted ( ));
25172522 }
25182523 }
25192524 }
0 commit comments