Skip to content

Commit 0663019

Browse files
pubiqqdsn5ft
authored andcommittedSep 7, 2023
[Color] Add ColorStateListDrawable support
Resolves #3538 GIT_ORIGIN_REV_ID=1bf9e320dc148e1bc959e7577372d3a393f35574 PiperOrigin-RevId: 563258432
1 parent b5d6f1a commit 0663019

File tree

8 files changed

+99
-87
lines changed

8 files changed

+99
-87
lines changed
 

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

+5-28
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import android.graphics.Canvas;
3535
import android.graphics.Rect;
3636
import android.graphics.drawable.ColorDrawable;
37-
import android.graphics.drawable.ColorStateListDrawable;
3837
import android.graphics.drawable.Drawable;
3938
import android.graphics.drawable.LayerDrawable;
4039
import android.os.Build;
@@ -53,7 +52,6 @@
5352
import android.widget.ScrollView;
5453
import androidx.annotation.ColorInt;
5554
import androidx.annotation.Dimension;
56-
import androidx.annotation.DoNotInline;
5755
import androidx.annotation.DrawableRes;
5856
import androidx.annotation.IdRes;
5957
import androidx.annotation.IntDef;
@@ -77,6 +75,7 @@
7775
import com.google.android.material.animation.AnimationUtils;
7876
import com.google.android.material.animation.ArgbEvaluatorCompat;
7977
import com.google.android.material.appbar.AppBarLayout.BaseBehavior.SavedState;
78+
import com.google.android.material.drawable.DrawableUtils;
8079
import com.google.android.material.internal.ThemeEnforcement;
8180
import com.google.android.material.motion.MotionUtils;
8281
import com.google.android.material.resources.MaterialResources;
@@ -262,10 +261,11 @@ public AppBarLayout(@NonNull Context context, @Nullable AttributeSet attrs, int
262261
MaterialResources.getColorStateList(
263262
context, a, R.styleable.AppBarLayout_liftOnScrollColor);
264263

265-
ColorStateList backgroundCSL = getBackgroundCSL();
266-
if (backgroundCSL != null) {
264+
ColorStateList backgroundColorStateList =
265+
DrawableUtils.getColorStateListOrNull(getBackground());
266+
if (backgroundColorStateList != null) {
267267
MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable();
268-
materialShapeDrawable.setFillColor(backgroundCSL);
268+
materialShapeDrawable.setFillColor(backgroundColorStateList);
269269
// If there is a lift on scroll color specified, we do not initialize the elevation overlay
270270
// and set the alpha to zero manually.
271271
if (liftOnScrollColor != null) {
@@ -326,17 +326,6 @@ public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets)
326326
});
327327
}
328328

329-
@Nullable
330-
private ColorStateList getBackgroundCSL() {
331-
Drawable background = getBackground();
332-
if (background instanceof ColorDrawable) {
333-
return ColorStateList.valueOf(((ColorDrawable) background).getColor());
334-
} else if (VERSION.SDK_INT >= VERSION_CODES.Q) {
335-
return DrawableHelperV29.maybeGetBackgroundCSL(background);
336-
}
337-
return null;
338-
}
339-
340329
private void initializeLiftOnScrollWithColor(MaterialShapeDrawable background) {
341330
MaterialShapeDrawable liftBackground = new MaterialShapeDrawable();
342331
liftBackground.setFillColor(liftOnScrollColor);
@@ -2612,16 +2601,4 @@ public void onOffsetChanged(
26122601
}
26132602
}
26142603
}
2615-
2616-
@RequiresApi(VERSION_CODES.Q)
2617-
private static class DrawableHelperV29 {
2618-
@DoNotInline
2619-
@Nullable
2620-
private static ColorStateList maybeGetBackgroundCSL(@Nullable Drawable background) {
2621-
if (background instanceof ColorStateListDrawable) {
2622-
return ((ColorStateListDrawable) background).getColorStateList();
2623-
}
2624-
return null;
2625-
}
2626-
}
26272604
}

‎lib/java/com/google/android/material/appbar/MaterialToolbar.java

+12-11
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import android.content.res.ColorStateList;
2626
import android.content.res.TypedArray;
2727
import android.graphics.Color;
28-
import android.graphics.drawable.ColorDrawable;
2928
import android.graphics.drawable.Drawable;
3029
import android.os.Build.VERSION_CODES;
3130
import androidx.appcompat.view.menu.MenuBuilder;
@@ -34,7 +33,6 @@
3433
import android.util.Pair;
3534
import android.view.Menu;
3635
import android.view.View;
37-
import android.view.View.MeasureSpec;
3836
import android.widget.ImageView;
3937
import android.widget.TextView;
4038
import androidx.annotation.ColorInt;
@@ -43,6 +41,7 @@
4341
import androidx.annotation.RequiresApi;
4442
import androidx.core.graphics.drawable.DrawableCompat;
4543
import androidx.core.view.ViewCompat;
44+
import com.google.android.material.drawable.DrawableUtils;
4645
import com.google.android.material.internal.ThemeEnforcement;
4746
import com.google.android.material.internal.ToolbarUtils;
4847
import com.google.android.material.shape.MaterialShapeDrawable;
@@ -378,16 +377,18 @@ public boolean isSubtitleCentered() {
378377

379378
private void initBackground(Context context) {
380379
Drawable background = getBackground();
381-
if (background != null && !(background instanceof ColorDrawable)) {
382-
return;
380+
ColorStateList backgroundColorStateList =
381+
background == null
382+
? ColorStateList.valueOf(Color.TRANSPARENT)
383+
: DrawableUtils.getColorStateListOrNull(background);
384+
385+
if (backgroundColorStateList != null) {
386+
MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable();
387+
materialShapeDrawable.setFillColor(backgroundColorStateList);
388+
materialShapeDrawable.initializeElevationOverlay(context);
389+
materialShapeDrawable.setElevation(ViewCompat.getElevation(this));
390+
ViewCompat.setBackground(this, materialShapeDrawable);
383391
}
384-
MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable();
385-
int backgroundColor =
386-
background != null ? ((ColorDrawable) background).getColor() : Color.TRANSPARENT;
387-
materialShapeDrawable.setFillColor(ColorStateList.valueOf(backgroundColor));
388-
materialShapeDrawable.initializeElevationOverlay(context);
389-
materialShapeDrawable.setElevation(ViewCompat.getElevation(this));
390-
ViewCompat.setBackground(this, materialShapeDrawable);
391392
}
392393

393394
@Nullable

‎lib/java/com/google/android/material/bottomsheet/BottomSheetDialog.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import android.content.res.ColorStateList;
2525
import android.content.res.TypedArray;
2626
import android.graphics.Color;
27-
import android.graphics.drawable.ColorDrawable;
2827
import android.os.Build;
2928
import android.os.Build.VERSION;
3029
import android.os.Build.VERSION_CODES;
@@ -50,6 +49,7 @@
5049
import androidx.core.view.WindowInsetsControllerCompat;
5150
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
5251
import com.google.android.material.internal.EdgeToEdgeUtils;
52+
import com.google.android.material.internal.ViewUtils;
5353
import com.google.android.material.motion.MaterialBackOrchestrator;
5454
import com.google.android.material.shape.MaterialShapeDrawable;
5555

@@ -467,12 +467,15 @@ private EdgeToEdgeCallback(
467467
if (backgroundTint != null) {
468468
// First check for a tint
469469
lightBottomSheet = isColorLight(backgroundTint.getDefaultColor());
470-
} else if (bottomSheet.getBackground() instanceof ColorDrawable) {
471-
// Then check for the background color
472-
lightBottomSheet = isColorLight(((ColorDrawable) bottomSheet.getBackground()).getColor());
473470
} else {
474-
// Otherwise don't change the status bar color
475-
lightBottomSheet = null;
471+
Integer backgroundColor = ViewUtils.getBackgroundColor(bottomSheet);
472+
if (backgroundColor != null) {
473+
// Then check for the background color
474+
lightBottomSheet = isColorLight(backgroundColor);
475+
} else {
476+
// Otherwise don't change the status bar color
477+
lightBottomSheet = null;
478+
}
476479
}
477480
}
478481

‎lib/java/com/google/android/material/drawable/DrawableUtils.java

+30
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import android.graphics.PorterDuff;
3030
import android.graphics.PorterDuff.Mode;
3131
import android.graphics.PorterDuffColorFilter;
32+
import android.graphics.drawable.ColorDrawable;
33+
import android.graphics.drawable.ColorStateListDrawable;
3234
import android.graphics.drawable.Drawable;
3335
import android.graphics.drawable.LayerDrawable;
3436
import android.graphics.drawable.RippleDrawable;
@@ -369,4 +371,32 @@ public static void setOutlineToPath(@NonNull final Outline outline, @NonNull fin
369371
outline.setConvexPath(path);
370372
}
371373
}
374+
375+
/**
376+
* Returns the {@link ColorStateList} if it can be retrieved from the {@code drawable}, or null
377+
* otherwise.
378+
*
379+
* <p>In particular:
380+
*
381+
* <ul>
382+
* <li>If the {@code drawable} is a {@link ColorStateListDrawable}, the method will return the
383+
* {@code drawable}'s {@link ColorStateList}.
384+
* <li>If the {@code drawable} is a {@link ColorDrawable}, the method will return a {@link
385+
* ColorStateList} containing the {@code drawable}'s color.
386+
* </ul>
387+
*/
388+
@Nullable
389+
public static ColorStateList getColorStateListOrNull(@Nullable final Drawable drawable) {
390+
if (drawable instanceof ColorDrawable) {
391+
return ColorStateList.valueOf(((ColorDrawable) drawable).getColor());
392+
}
393+
394+
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
395+
if (drawable instanceof ColorStateListDrawable) {
396+
return ((ColorStateListDrawable) drawable).getColorStateList();
397+
}
398+
}
399+
400+
return null;
401+
}
372402
}

‎lib/java/com/google/android/material/internal/ViewUtils.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
import static androidx.core.content.ContextCompat.getSystemService;
2323

2424
import android.content.Context;
25+
import android.content.res.ColorStateList;
2526
import android.content.res.Resources;
2627
import android.content.res.TypedArray;
2728
import android.graphics.PorterDuff;
2829
import android.graphics.Rect;
2930
import android.graphics.drawable.ColorDrawable;
31+
import android.graphics.drawable.ColorStateListDrawable;
3032
import android.os.Build;
3133
import android.os.Build.VERSION;
3234
import android.os.Build.VERSION_CODES;
@@ -48,6 +50,7 @@
4850
import androidx.core.view.ViewCompat;
4951
import androidx.core.view.WindowInsetsCompat;
5052
import androidx.core.view.WindowInsetsControllerCompat;
53+
import com.google.android.material.drawable.DrawableUtils;
5154
import java.util.ArrayList;
5255
import java.util.List;
5356

@@ -436,13 +439,22 @@ public static void removeOnGlobalLayoutListener(
436439
}
437440

438441
/**
439-
* Returns the provided view's background color, if it has ColorDrawable as its background, or
440-
* {@code null} if the background has a different drawable type.
442+
* Returns the color if it can be retrieved from the {@code view}'s background drawable, or null
443+
* otherwise.
444+
*
445+
* <p>In particular:
446+
*
447+
* <ul>
448+
* <li>If the {@code view}'s background drawable is a {@link ColorDrawable}, the method will
449+
* return the drawable's color.
450+
* <li>If the {@code view}'s background drawable is a {@link ColorStateListDrawable}, the method
451+
* will return the default color of the drawable's {@link ColorStateList}.
452+
* </ul>
441453
*/
442454
@Nullable
443455
public static Integer getBackgroundColor(@NonNull View view) {
444-
return view.getBackground() instanceof ColorDrawable
445-
? ((ColorDrawable) view.getBackground()).getColor()
446-
: null;
456+
final ColorStateList backgroundColorStateList =
457+
DrawableUtils.getColorStateListOrNull(view.getBackground());
458+
return backgroundColorStateList != null ? backgroundColorStateList.getDefaultColor() : null;
447459
}
448460
}

‎lib/java/com/google/android/material/navigation/NavigationBarView.java

+15-19
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import android.content.Context;
2626
import android.content.res.ColorStateList;
2727
import android.content.res.TypedArray;
28-
import android.graphics.drawable.ColorDrawable;
2928
import android.graphics.drawable.Drawable;
3029
import android.os.Build.VERSION;
3130
import android.os.Build.VERSION_CODES;
@@ -56,6 +55,7 @@
5655
import androidx.core.view.ViewCompat;
5756
import androidx.customview.view.AbsSavedState;
5857
import com.google.android.material.badge.BadgeDrawable;
58+
import com.google.android.material.drawable.DrawableUtils;
5959
import com.google.android.material.internal.ThemeEnforcement;
6060
import com.google.android.material.resources.MaterialResources;
6161
import com.google.android.material.shape.MaterialShapeDrawable;
@@ -195,10 +195,20 @@ public NavigationBarView(
195195
setItemTextColor(attributes.getColorStateList(R.styleable.NavigationBarView_itemTextColor));
196196
}
197197

198-
if (getBackground() == null || getBackground() instanceof ColorDrawable) {
199-
// Add a MaterialShapeDrawable as background that supports tinting in every API level.
200-
ViewCompat.setBackground(this, createMaterialShapeDrawableBackground(context,
201-
ShapeAppearanceModel.builder(context, attrs, defStyleAttr, defStyleRes).build()));
198+
// Add a MaterialShapeDrawable as background that supports tinting in every API level.
199+
Drawable background = getBackground();
200+
ColorStateList backgroundColorStateList = DrawableUtils.getColorStateListOrNull(background);
201+
202+
if (background == null || backgroundColorStateList != null) {
203+
ShapeAppearanceModel shapeAppearanceModel =
204+
ShapeAppearanceModel.builder(context, attrs, defStyleAttr, defStyleRes).build();
205+
MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
206+
if (backgroundColorStateList != null) {
207+
// Setting fill color with a transparent CSL will disable the tint list.
208+
materialShapeDrawable.setFillColor(backgroundColorStateList);
209+
}
210+
materialShapeDrawable.initializeElevationOverlay(context);
211+
ViewCompat.setBackground(this, materialShapeDrawable);
202212
}
203213

204214
if (attributes.hasValue(R.styleable.NavigationBarView_itemPaddingTop)) {
@@ -306,20 +316,6 @@ public void onMenuModeChange(MenuBuilder menu) {}
306316
});
307317
}
308318

309-
@NonNull
310-
private MaterialShapeDrawable createMaterialShapeDrawableBackground(
311-
Context context, ShapeAppearanceModel shapeAppearanceModel) {
312-
MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable();
313-
Drawable originalBackground = getBackground();
314-
if (originalBackground instanceof ColorDrawable) {
315-
materialShapeDrawable.setFillColor(
316-
ColorStateList.valueOf(((ColorDrawable) originalBackground).getColor()));
317-
}
318-
materialShapeDrawable.initializeElevationOverlay(context);
319-
materialShapeDrawable.setShapeAppearanceModel(shapeAppearanceModel);
320-
return materialShapeDrawable;
321-
}
322-
323319
@Override
324320
protected void onAttachedToWindow() {
325321
super.onAttachedToWindow();

‎lib/java/com/google/android/material/navigation/NavigationView.java

+7-14
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
import android.graphics.Color;
3131
import android.graphics.Rect;
3232
import android.graphics.RectF;
33-
import android.graphics.drawable.ColorDrawable;
34-
import android.graphics.drawable.ColorStateListDrawable;
3533
import android.graphics.drawable.Drawable;
3634
import android.graphics.drawable.InsetDrawable;
3735
import android.graphics.drawable.RippleDrawable;
@@ -77,6 +75,7 @@
7775
import androidx.drawerlayout.widget.DrawerLayout;
7876
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener;
7977
import androidx.drawerlayout.widget.DrawerLayout.SimpleDrawerListener;
78+
import com.google.android.material.drawable.DrawableUtils;
8079
import com.google.android.material.internal.ContextUtils;
8180
import com.google.android.material.internal.NavigationMenu;
8281
import com.google.android.material.internal.NavigationMenuPresenter;
@@ -201,23 +200,17 @@ public NavigationView(@NonNull Context context, @Nullable AttributeSet attrs, in
201200
drawerLayoutCornerSize =
202201
a.getDimensionPixelSize(R.styleable.NavigationView_drawerLayoutCornerSize, 0);
203202

204-
Drawable background = getBackground();
205203
// Set the background to a MaterialShapeDrawable if it hasn't been set or if it can be converted
206204
// to a MaterialShapeDrawable.
207-
if (background == null
208-
|| background instanceof ColorDrawable
209-
|| (VERSION.SDK_INT >= VERSION_CODES.Q
210-
&& background instanceof ColorStateListDrawable)) {
205+
Drawable background = getBackground();
206+
ColorStateList backgroundColorStateList = DrawableUtils.getColorStateListOrNull(background);
207+
208+
if (background == null || backgroundColorStateList != null) {
211209
ShapeAppearanceModel shapeAppearanceModel =
212210
ShapeAppearanceModel.builder(context, attrs, defStyleAttr, DEF_STYLE_RES).build();
213211
MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
214-
if (background instanceof ColorDrawable) {
215-
materialShapeDrawable.setFillColor(
216-
ColorStateList.valueOf(((ColorDrawable) background).getColor()));
217-
}
218-
if (VERSION.SDK_INT >= VERSION_CODES.Q && background instanceof ColorStateListDrawable) {
219-
materialShapeDrawable.setFillColor(
220-
((ColorStateListDrawable) background).getColorStateList());
212+
if (backgroundColorStateList != null) {
213+
materialShapeDrawable.setFillColor(backgroundColorStateList);
221214
}
222215
materialShapeDrawable.initializeElevationOverlay(context);
223216
ViewCompat.setBackground(this, materialShapeDrawable);

‎lib/java/com/google/android/material/tabs/TabLayout.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import android.graphics.Canvas;
3737
import android.graphics.Color;
3838
import android.graphics.Rect;
39-
import android.graphics.drawable.ColorDrawable;
4039
import android.graphics.drawable.Drawable;
4140
import android.graphics.drawable.GradientDrawable;
4241
import android.graphics.drawable.LayerDrawable;
@@ -546,10 +545,11 @@ public TabLayout(@NonNull Context context, @Nullable AttributeSet attrs, int def
546545
DEF_STYLE_RES,
547546
R.styleable.TabLayout_tabTextAppearance);
548547

549-
if (getBackground() instanceof ColorDrawable) {
550-
ColorDrawable background = (ColorDrawable) getBackground();
548+
ColorStateList backgroundColorStateList =
549+
DrawableUtils.getColorStateListOrNull(getBackground());
550+
if (backgroundColorStateList != null) {
551551
MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable();
552-
materialShapeDrawable.setFillColor(ColorStateList.valueOf(background.getColor()));
552+
materialShapeDrawable.setFillColor(backgroundColorStateList);
553553
materialShapeDrawable.initializeElevationOverlay(context);
554554
materialShapeDrawable.setElevation(ViewCompat.getElevation(this));
555555
ViewCompat.setBackground(this, materialShapeDrawable);

0 commit comments

Comments
 (0)
Please sign in to comment.