Skip to content

Commit bc46fe8

Browse files
committed
[AppBarLayout] Use a uniform way to determine the target scrolling view
1 parent 90d6583 commit bc46fe8

File tree

1 file changed

+59
-54
lines changed

1 file changed

+59
-54
lines changed

lib/java/com/google/android/material/appbar/AppBarLayout.java

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
import android.view.ViewGroup;
4747
import android.view.ViewOutlineProvider;
4848
import android.view.animation.Interpolator;
49-
import android.widget.AbsListView;
5049
import android.widget.LinearLayout;
5150
import android.widget.ScrollView;
5251
import androidx.annotation.ColorInt;
@@ -63,7 +62,6 @@
6362
import androidx.core.graphics.drawable.DrawableCompat;
6463
import androidx.core.util.ObjectsCompat;
6564
import androidx.core.view.AccessibilityDelegateCompat;
66-
import androidx.core.view.NestedScrollingChild;
6765
import androidx.core.view.ViewCompat;
6866
import androidx.core.view.ViewCompat.NestedScrollType;
6967
import 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

Comments
 (0)