@@ -225,9 +225,9 @@ public abstract void onUpdate(
225225 private boolean lifted ;
226226
227227 private boolean liftOnScroll ;
228+ @ Nullable private ColorStateList liftOnScrollColor ;
228229 @ IdRes private int liftOnScrollTargetViewId ;
229230 @ Nullable private WeakReference <View > liftOnScrollTargetView ;
230- private final boolean hasLiftOnScrollColor ;
231231 @ Nullable private ValueAnimator liftOnScrollColorAnimator ;
232232 @ Nullable private AnimatorUpdateListener liftOnScrollColorUpdateListener ;
233233 private final List <LiftOnScrollListener > liftOnScrollListeners = new ArrayList <>();
@@ -239,6 +239,7 @@ public abstract void onUpdate(
239239
240240 private int [] tmpStatesArray ;
241241
242+ @ ColorInt private int backgroundOriginalColor ;
242243 @ Nullable private Drawable statusBarForeground ;
243244 @ Nullable private Integer statusBarForegroundOriginalColor ;
244245
@@ -272,25 +273,8 @@ public AppBarLayout(@NonNull Context context, @Nullable AttributeSet attrs, int
272273 ThemeEnforcement .obtainStyledAttributes (
273274 context , attrs , R .styleable .AppBarLayout , defStyleAttr , DEF_STYLE_RES );
274275
275- setBackground (a .getDrawable (R .styleable .AppBarLayout_android_background ));
276-
277- ColorStateList liftOnScrollColor =
276+ liftOnScrollColor =
278277 MaterialResources .getColorStateList (context , a , R .styleable .AppBarLayout_liftOnScrollColor );
279- hasLiftOnScrollColor = liftOnScrollColor != null ;
280-
281- ColorStateList originalBackgroundColor = DrawableUtils .getColorStateListOrNull (getBackground ());
282- if (originalBackgroundColor != null ) {
283- MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable ();
284- materialShapeDrawable .setFillColor (originalBackgroundColor );
285- // If there is a lift on scroll color specified, we do not initialize the elevation overlay
286- // and set the alpha to zero manually.
287- if (liftOnScrollColor != null ) {
288- initializeLiftOnScrollWithColor (
289- materialShapeDrawable , originalBackgroundColor , liftOnScrollColor );
290- } else {
291- initializeLiftOnScrollWithElevation (context , materialShapeDrawable );
292- }
293- }
294278
295279 liftOnScrollColorDuration =
296280 MotionUtils .resolveThemeDuration (
@@ -313,6 +297,9 @@ public AppBarLayout(@NonNull Context context, @Nullable AttributeSet attrs, int
313297 this , a .getDimensionPixelSize (R .styleable .AppBarLayout_elevation , 0 ));
314298 }
315299
300+ // Set the background drawable last to ensure that the background is updated for lift on scroll.
301+ setBackground (a .getDrawable (R .styleable .AppBarLayout_android_background ));
302+
316303 if (VERSION .SDK_INT >= VERSION_CODES .O ) {
317304 // In O+, we have these values set in the style. Since there is no defStyleAttr for
318305 // AppBarLayout at the AppCompat level, check for these attributes here.
@@ -346,19 +333,49 @@ public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets)
346333 });
347334 }
348335
336+ private Drawable maybeCreateLiftOnScrollBackground (
337+ @ NonNull Context context , @ NonNull Drawable originalBackground ) {
338+ MaterialShapeDrawable materialShapeDrawable =
339+ maybeConvertToMaterialShapeDrawable (originalBackground );
340+ if (materialShapeDrawable == null || materialShapeDrawable .getFillColor () == null ) {
341+ return originalBackground ;
342+ }
343+ backgroundOriginalColor = materialShapeDrawable .getFillColor ().getDefaultColor ();
344+ // If there is a lift on scroll color specified, we do not initialize the elevation overlay
345+ // and set the alpha to zero manually.
346+ if (liftOnScrollColor != null ) {
347+ initializeLiftOnScrollWithColor (materialShapeDrawable , liftOnScrollColor );
348+ } else {
349+ initializeLiftOnScrollWithElevation (context , materialShapeDrawable );
350+ }
351+ return materialShapeDrawable ;
352+ }
353+
354+ @ Nullable
355+ private MaterialShapeDrawable maybeConvertToMaterialShapeDrawable (Drawable originalBackground ) {
356+ if (originalBackground instanceof MaterialShapeDrawable ) {
357+ return (MaterialShapeDrawable ) originalBackground ;
358+ }
359+ ColorStateList originalBackgroundColor =
360+ DrawableUtils .getColorStateListOrNull (originalBackground );
361+ if (originalBackgroundColor == null ) {
362+ return null ;
363+ }
364+ MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable ();
365+ materialShapeDrawable .setFillColor (originalBackgroundColor );
366+ return materialShapeDrawable ;
367+ }
368+
349369 private void initializeLiftOnScrollWithColor (
350370 MaterialShapeDrawable background ,
351- @ NonNull ColorStateList originalBackgroundColor ,
352371 @ NonNull ColorStateList liftOnScrollColor ) {
353372 Integer colorSurface = MaterialColors .getColorOrNull (getContext (), R .attr .colorSurface );
354373 liftOnScrollColorUpdateListener =
355374 valueAnimator -> {
356375 float liftProgress = (float ) valueAnimator .getAnimatedValue ();
357376 int mixedColor =
358377 MaterialColors .layer (
359- originalBackgroundColor .getDefaultColor (),
360- liftOnScrollColor .getDefaultColor (),
361- liftProgress );
378+ backgroundOriginalColor , liftOnScrollColor .getDefaultColor (), liftProgress );
362379 background .setFillColor (ColorStateList .valueOf (mixedColor ));
363380 if (statusBarForeground != null
364381 && statusBarForegroundOriginalColor != null
@@ -380,8 +397,6 @@ private void initializeLiftOnScrollWithColor(
380397 }
381398 }
382399 };
383-
384- setBackground (background );
385400 }
386401
387402 private void initializeLiftOnScrollWithElevation (
@@ -402,8 +417,6 @@ private void initializeLiftOnScrollWithElevation(
402417 elevation , background .getResolvedTintColor (), elevation / appBarElevation );
403418 }
404419 };
405-
406- setBackground (background );
407420 }
408421
409422 /**
@@ -576,6 +589,11 @@ private Integer extractStatusBarForegroundColor() {
576589 return null ;
577590 }
578591
592+ @ Override
593+ public void setBackground (Drawable background ) {
594+ super .setBackground (maybeCreateLiftOnScrollBackground (getContext (), background ));
595+ }
596+
579597 @ Override
580598 public void draw (@ NonNull Canvas canvas ) {
581599 super .draw (canvas );
@@ -1092,7 +1110,7 @@ boolean setLiftedState(boolean lifted, boolean force) {
10921110 this .lifted = lifted ;
10931111 refreshDrawableState ();
10941112 if (isLiftOnScrollCompatibleBackground ()) {
1095- if (hasLiftOnScrollColor ) {
1113+ if (liftOnScrollColor != null ) {
10961114 // Only start the liftOnScrollColor based animation because the elevation based
10971115 // animation will happen via the lifted drawable state change and state list animator.
10981116 startLiftOnScrollColorAnimation (lifted ? 0 : 1 , lifted ? 1 : 0 );
@@ -1164,6 +1182,17 @@ public void setLiftOnScrollTargetViewId(@IdRes int liftOnScrollTargetViewId) {
11641182 clearLiftOnScrollTargetView ();
11651183 }
11661184
1185+ /** Sets the color of the {@link AppBarLayout} when it is fully lifted. */
1186+ public void setLiftOnScrollColor (@ Nullable ColorStateList liftOnScrollColor ) {
1187+ if (this .liftOnScrollColor != liftOnScrollColor ) {
1188+ this .liftOnScrollColor = liftOnScrollColor ;
1189+ // Force recreating the background drawable for the lift on scroll color change. The
1190+ // background could be potentially switched between liftOnScroll with color and liftOnScroll
1191+ // with elevation, based on whether the liftOnScroll color is null or not.
1192+ setBackground (getBackground ());
1193+ }
1194+ }
1195+
11671196 /**
11681197 * Returns the id of the view that the {@link AppBarLayout} should use to determine whether it
11691198 * should be lifted.
0 commit comments