Google's official Material Design components library for Android applications with comprehensive UI components, theming, and animations.
—
Material Design theming system including colors, shapes, typography, elevation, and dynamic colors.
import com.google.android.material.color.MaterialColors;
import com.google.android.material.color.DynamicColors;
import com.google.android.material.color.ColorRoles;
import com.google.android.material.shape.ShapeAppearanceModel;
import com.google.android.material.shape.MaterialShapeDrawable;
import com.google.android.material.shape.CornerTreatment;
import com.google.android.material.shape.CornerSize;
import com.google.android.material.shape.AbsoluteCornerSize;
import com.google.android.material.shape.RelativeCornerSize;
import com.google.android.material.shape.RoundedCornerTreatment;
import com.google.android.material.shape.CutCornerTreatment;
import com.google.android.material.elevation.ElevationOverlayProvider;
import com.google.android.material.resources.MaterialResources;
import com.google.android.material.typography.TypographyUtils;Utility class for working with Material Design colors and theme attributes.
class MaterialColors {
// Get color from theme attributes
static int getColor(View view, @AttrRes int colorAttributeResId);
static int getColor(Context context, @AttrRes int colorAttributeResId, int defaultValue);
static int getColor(View view, @AttrRes int colorAttributeResId, int defaultValue);
// Get ColorStateList from theme attributes
static ColorStateList getColorStateList(View view, @AttrRes int colorAttributeResId);
static ColorStateList getColorStateList(Context context, @AttrRes int colorAttributeResId, ColorStateList defaultValue);
// Color layering and blending
static int layer(View view, @AttrRes int backgroundColorAttributeResId, @AttrRes int overlayColorAttributeResId);
static int layer(View view, @AttrRes int backgroundColorAttributeResId, @AttrRes int overlayColorAttributeResId, float overlayAlpha);
static int layer(@ColorInt int backgroundColor, @ColorInt int overlayColor, @FloatRange(from = 0.0, to = 1.0) float overlayAlpha);
// Alpha composition
static int compositeARGBWithAlpha(@ColorInt int originalColor, @IntRange(from = 0, to = 255) int alpha);
// Color analysis
static boolean isColorLight(@ColorInt int color);
}// Get theme colors
int primaryColor = MaterialColors.getColor(view, com.google.android.material.R.attr.colorPrimary);
int surfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface, Color.WHITE);
// Get ColorStateList for different states
ColorStateList primaryColorStateList = MaterialColors.getColorStateList(
view, com.google.android.material.R.attr.colorPrimary);
// Layer colors with alpha
int layeredColor = MaterialColors.layer(
view,
com.google.android.material.R.attr.colorSurface,
com.google.android.material.R.attr.colorPrimary,
0.08f // 8% alpha overlay
);
// Apply elevation overlay
int elevatedSurfaceColor = MaterialColors.layer(surfaceColor, primaryColor, 0.05f);
// Check if color is light for contrast decisions
boolean isLight = MaterialColors.isColorLight(backgroundColor);
int textColor = isLight ? Color.BLACK : Color.WHITE;
// Composite color with alpha
int transparentColor = MaterialColors.compositeARGBWithAlpha(primaryColor, 128); // 50% alphaSupport for Android 12+ dynamic color theming (Material You).
class DynamicColors {
// Apply dynamic colors to activities
static void applyToActivitiesIfAvailable(Application application);
static void applyToActivitiesIfAvailable(Application application, DynamicColorsOptions options);
static void applyToActivityIfAvailable(Activity activity);
static void applyToActivityIfAvailable(Activity activity, DynamicColorsOptions options);
// Check dynamic color availability
static boolean isDynamicColorAvailable();
// Context wrapping for dynamic colors
static Context wrapContextIfAvailable(Context context);
static Context wrapContextIfAvailable(Context context, DynamicColorsOptions options);
}
class DynamicColorsOptions {
int getThemeOverlay();
OnAppliedCallback getOnAppliedCallback();
Precondition getPrecondition();
interface OnAppliedCallback {
void onApplied(DynamicColorsOptions options);
}
interface Precondition {
boolean shouldApplyDynamicColors(Activity activity, int theme);
}
}// Enable dynamic colors globally in Application class
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Apply dynamic colors to all activities if available
DynamicColors.applyToActivitiesIfAvailable(this);
// Or with options
DynamicColorsOptions options = new DynamicColorsOptions.Builder()
.setOnAppliedCallback(appliedOptions -> {
Log.d("DynamicColors", "Dynamic colors applied");
})
.build();
DynamicColors.applyToActivitiesIfAvailable(this, options);
}
}
// Check if dynamic colors are available
if (DynamicColors.isDynamicColorAvailable()) {
// Use dynamic colors
DynamicColors.applyToActivityIfAvailable(this);
} else {
// Fallback to static colors
setTheme(R.style.AppTheme_StaticColors);
}
// Wrap context for dynamic colors
Context dynamicContext = DynamicColors.wrapContextIfAvailable(this);
LayoutInflater.from(dynamicContext).inflate(R.layout.dynamic_layout, parent);Represents semantic color roles in Material Design color system.
class ColorRoles {
@ColorInt int getAccent();
@ColorInt int getOnAccent();
@ColorInt int getAccentContainer();
@ColorInt int getOnAccentContainer();
}Defines the appearance and shape characteristics of Material components.
class ShapeAppearanceModel {
// Factory methods
static Builder builder();
static Builder builder(Context context, @StyleRes int styleRes, @StyleRes int defaultStyleRes);
static Builder builder(Context context, AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes);
// Corner treatments
CornerTreatment getTopLeftCorner();
CornerTreatment getTopRightCorner();
CornerTreatment getBottomRightCorner();
CornerTreatment getBottomLeftCorner();
// Corner sizes
CornerSize getTopLeftCornerSize();
CornerSize getTopRightCornerSize();
CornerSize getBottomRightCornerSize();
CornerSize getBottomLeftCornerSize();
// Edge treatments
EdgeTreatment getTopEdge();
EdgeTreatment getRightEdge();
EdgeTreatment getBottomEdge();
EdgeTreatment getLeftEdge();
// Builder for modifications
Builder toBuilder();
// Transform corner sizes
ShapeAppearanceModel withTransformedCornerSizes(CornerSizeUnaryOperator cornerSizeUnaryOperator);
}
class ShapeAppearanceModel.Builder {
// Set all corners
Builder setAllCorners(CornerTreatment cornerTreatment);
Builder setAllCornerSizes(float cornerSize);
Builder setAllCornerSizes(CornerSize cornerSize);
// Individual corners
Builder setTopLeftCorner(CornerTreatment cornerTreatment);
Builder setTopLeftCornerSize(float cornerSize);
Builder setTopLeftCornerSize(CornerSize cornerSize);
Builder setTopRightCorner(CornerTreatment cornerTreatment);
Builder setTopRightCornerSize(float cornerSize);
Builder setTopRightCornerSize(CornerSize cornerSize);
Builder setBottomLeftCorner(CornerTreatment cornerTreatment);
Builder setBottomLeftCornerSize(float cornerSize);
Builder setBottomLeftCornerSize(CornerSize cornerSize);
Builder setBottomRightCorner(CornerTreatment cornerTreatment);
Builder setBottomRightCornerSize(float cornerSize);
Builder setBottomRightCornerSize(CornerSize cornerSize);
// Edge treatments
Builder setAllEdges(EdgeTreatment edgeTreatment);
Builder setTopEdge(EdgeTreatment topEdge);
Builder setRightEdge(EdgeTreatment rightEdge);
Builder setBottomEdge(EdgeTreatment bottomEdge);
Builder setLeftEdge(EdgeTreatment leftEdge);
// Build
ShapeAppearanceModel build();
}
interface ShapeAppearanceModel.CornerSizeUnaryOperator {
CornerSize apply(CornerSize cornerSize);
}// Create basic rounded shape
ShapeAppearanceModel roundedShape = ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 16f)
.build();
// Create cut corner shape
ShapeAppearanceModel cutShape = ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.CUT, 8f)
.build();
// Mixed corner styles
ShapeAppearanceModel mixedShape = ShapeAppearanceModel.builder()
.setTopLeftCorner(CornerFamily.ROUNDED, 16f)
.setTopRightCorner(CornerFamily.ROUNDED, 16f)
.setBottomLeftCorner(CornerFamily.CUT, 8f)
.setBottomRightCorner(CornerFamily.CUT, 8f)
.build();
// Pill shape (fully rounded)
ShapeAppearanceModel pillShape = ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 50f) // 50% of height
.build();
// Apply to MaterialCardView
MaterialCardView cardView = findViewById(R.id.card_view);
cardView.setShapeAppearanceModel(roundedShape);
// Apply to MaterialButton
MaterialButton button = findViewById(R.id.button);
button.setShapeAppearanceModel(pillShape);
// Transform existing shape (add 8dp to all corners)
ShapeAppearanceModel transformedShape = existingShape.withTransformedCornerSizes(
cornerSize -> new AbsoluteCornerSize(cornerSize.getCornerSize(bounds) + 8f)
);Drawable that renders Material Design shapes with fill, stroke, and elevation.
class MaterialShapeDrawable extends Drawable {
// Constructors
MaterialShapeDrawable();
MaterialShapeDrawable(ShapeAppearanceModel shapeAppearanceModel);
MaterialShapeDrawable(MaterialShapeDrawableState drawableState);
// Factory methods with elevation overlay
static MaterialShapeDrawable createWithElevationOverlay(Context context);
static MaterialShapeDrawable createWithElevationOverlay(Context context, float elevation);
// Shape appearance
void setShapeAppearanceModel(ShapeAppearanceModel shapeAppearanceModel);
ShapeAppearanceModel getShapeAppearanceModel();
// Fill color
void setFillColor(ColorStateList fillColor);
ColorStateList getFillColor();
// Stroke
void setStroke(float strokeWidth, @ColorInt int strokeColor);
void setStroke(float strokeWidth, ColorStateList strokeColor);
float getStrokeWidth();
ColorStateList getStrokeColor();
// Elevation and shadow
void setElevation(float elevation);
float getElevation();
void setShadowColor(@ColorInt int shadowColor);
int getShadowColor();
void setUseTintColorForShadow(boolean useTintColorForShadow);
boolean isUseTintColorForShadow();
void setShadowCompatibilityMode(int mode);
int getShadowCompatibilityMode();
// Paint style
void setPaintStyle(Paint.Style style);
Paint.Style getPaintStyle();
// Interpolation for animations
void setInterpolation(float interpolation);
float getInterpolation();
// Parent elevation for relative shadows
void setParentAbsoluteElevation(float parentAbsoluteElevation);
float getParentAbsoluteElevation();
}public static final int SHADOW_COMPAT_MODE_DEFAULT = 0;
public static final int SHADOW_COMPAT_MODE_ALWAYS = 1;
public static final int SHADOW_COMPAT_MODE_NEVER = 2;// Create shape drawable with elevation
MaterialShapeDrawable shapeDrawable = MaterialShapeDrawable.createWithElevationOverlay(this, 8f);
// Configure shape
ShapeAppearanceModel shape = ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 12f)
.build();
shapeDrawable.setShapeAppearanceModel(shape);
// Configure colors
shapeDrawable.setFillColor(ColorStateList.valueOf(
MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface)));
shapeDrawable.setStroke(2f, MaterialColors.getColor(this,
com.google.android.material.R.attr.colorOutline));
// Apply to view background
View customView = findViewById(R.id.custom_view);
customView.setBackground(shapeDrawable);
// Animate shape changes
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.addUpdateListener(animation -> {
float progress = (float) animation.getAnimatedValue();
shapeDrawable.setInterpolation(progress);
});
animator.start();
// Custom shape for specific use case
MaterialShapeDrawable buttonBackground = new MaterialShapeDrawable();
buttonBackground.setShapeAppearanceModel(ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 20f)
.build());
buttonBackground.setFillColor(ColorStateList.valueOf(primaryColor));
buttonBackground.setElevation(4f);
MaterialButton customButton = findViewById(R.id.custom_button);
customButton.setBackground(buttonBackground);Different corner styles and sizing approaches.
class RoundedCornerTreatment extends CornerTreatment {
RoundedCornerTreatment();
RoundedCornerTreatment(float radius);
}
class CutCornerTreatment extends CornerTreatment {
CutCornerTreatment();
CutCornerTreatment(float size);
}interface CornerSize {
float getCornerSize(RectF bounds);
}
class AbsoluteCornerSize implements CornerSize {
AbsoluteCornerSize(float size);
float getCornerSize(RectF bounds);
}
class RelativeCornerSize implements CornerSize {
RelativeCornerSize(@FloatRange(from = 0.0f, to = 1.0f) float percent);
float getCornerSize(RectF bounds);
}// Absolute corner size (fixed pixels/dp)
CornerSize absoluteCorner = new AbsoluteCornerSize(16f); // 16dp corners
// Relative corner size (percentage of view size)
CornerSize relativeCorner = new RelativeCornerSize(0.5f); // 50% = circular
// Custom corner treatments
CornerTreatment roundedCorner = new RoundedCornerTreatment(12f);
CornerTreatment cutCorner = new CutCornerTreatment(8f);
// Apply to shape
ShapeAppearanceModel customShape = ShapeAppearanceModel.builder()
.setTopLeftCorner(roundedCorner)
.setTopLeftCornerSize(absoluteCorner)
.setBottomRightCorner(cutCorner)
.setBottomRightCornerSize(relativeCorner)
.build();Provides elevation overlay colors for dark themes.
class ElevationOverlayProvider {
ElevationOverlayProvider(Context context);
// Overlay composition
@ColorInt int compositeOverlayWithThemeSurfaceColorIfNeeded(float elevation);
@ColorInt int compositeOverlayIfNeeded(@ColorInt int backgroundColor, float elevation);
@ColorInt int compositeOverlay(@ColorInt int backgroundColor, float elevation);
// Overlay alpha calculation
int calculateOverlayAlpha(float elevation);
// Theme colors
@ColorInt int getThemeSurfaceColor();
@ColorInt int getThemeElevationOverlayColor();
boolean isThemeElevationOverlayEnabled();
}ElevationOverlayProvider elevationProvider = new ElevationOverlayProvider(this);
// Get surface color with elevation overlay
int surfaceColor = elevationProvider.getThemeSurfaceColor();
int elevatedSurfaceColor = elevationProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(8f);
// Apply to custom view background
View elevatedView = findViewById(R.id.elevated_view);
elevatedView.setBackgroundColor(elevatedSurfaceColor);
// Custom elevation overlay
int customColor = Color.parseColor("#121212"); // Dark surface
int overlayColor = elevationProvider.compositeOverlay(customColor, 16f);Utility methods for accessing Material Design resources and attributes.
class MaterialResources {
// ColorStateList from attributes
static ColorStateList getColorStateList(Context context, TypedArray attributes, @StyleableRes int index);
static ColorStateList getColorStateList(Context context, @ColorRes int colorRes);
// Drawable from attributes
static Drawable getDrawable(Context context, TypedArray attributes, @StyleableRes int index);
// Text appearance from attributes
static TextAppearance getTextAppearance(Context context, TypedArray attributes, @StyleableRes int index);
// Dimension from attributes
static int getDimensionPixelSize(Context context, TypedArray attributes, @StyleableRes int index, int defaultValue);
// Boolean and integer resources
static boolean getBoolean(Context context, @BoolRes int boolRes, boolean defaultValue);
static int getInteger(Context context, @IntegerRes int integerRes, int defaultValue);
}Utilities for applying Material Design typography.
class TypographyUtils {
// Apply text appearance to TextView
static void applyTypography(TextView textView, TextAppearance textAppearance);
// Resolve text appearance from style resource
static TextAppearance resolveTextAppearance(Context context, @StyleRes int textAppearanceStyleRes);
}Example showing comprehensive Material theming implementation:
public class ThemingExampleActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Apply dynamic colors if available
if (DynamicColors.isDynamicColorAvailable()) {
DynamicColors.applyToActivityIfAvailable(this);
}
setContentView(R.layout.activity_theming_example);
setupCustomTheming();
setupShapeTheming();
setupElevationTheming();
}
private void setupCustomTheming() {
// Get theme colors
int primaryColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorPrimary);
int surfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface);
int onSurfaceColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface);
// Apply colors to custom views
View headerView = findViewById(R.id.header_view);
headerView.setBackgroundColor(primaryColor);
TextView titleText = findViewById(R.id.title_text);
titleText.setTextColor(MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnPrimary));
// Create layered color for subtle accent
int accentColor = MaterialColors.layer(surfaceColor, primaryColor, 0.12f);
View accentView = findViewById(R.id.accent_view);
accentView.setBackgroundColor(accentColor);
// Dynamic text color based on background
boolean isLightBackground = MaterialColors.isColorLight(surfaceColor);
int adaptiveTextColor = isLightBackground ?
MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface) :
MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface);
TextView bodyText = findViewById(R.id.body_text);
bodyText.setTextColor(adaptiveTextColor);
}
private void setupShapeTheming() {
// Card with custom shape
MaterialCardView cardView = findViewById(R.id.themed_card);
ShapeAppearanceModel cardShape = ShapeAppearanceModel.builder()
.setTopLeftCorner(CornerFamily.ROUNDED, 16f)
.setTopRightCorner(CornerFamily.ROUNDED, 16f)
.setBottomLeftCorner(CornerFamily.CUT, 8f)
.setBottomRightCorner(CornerFamily.CUT, 8f)
.build();
cardView.setShapeAppearanceModel(cardShape);
// Button with pill shape
MaterialButton pillButton = findViewById(R.id.pill_button);
ShapeAppearanceModel pillShape = ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 50f)
.build();
pillButton.setShapeAppearanceModel(pillShape);
// Image with custom shape
ShapeableImageView imageView = findViewById(R.id.shaped_image);
ShapeAppearanceModel imageShape = ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 12f)
.build();
imageView.setShapeAppearanceModel(imageShape);
imageView.setStrokeWidth(2f);
imageView.setStrokeColor(ColorStateList.valueOf(
MaterialColors.getColor(this, com.google.android.material.R.attr.colorOutline)));
// Custom drawable with shape
MaterialShapeDrawable customDrawable = new MaterialShapeDrawable();
customDrawable.setShapeAppearanceModel(ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 8f)
.build());
customDrawable.setFillColor(ColorStateList.valueOf(
MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceVariant)));
customDrawable.setStroke(1f, MaterialColors.getColor(this,
com.google.android.material.R.attr.colorOutline));
View customView = findViewById(R.id.custom_shaped_view);
customView.setBackground(customDrawable);
}
private void setupElevationTheming() {
ElevationOverlayProvider elevationProvider = new ElevationOverlayProvider(this);
// Apply elevation overlays to views
View[] elevatedViews = {
findViewById(R.id.elevation_2dp),
findViewById(R.id.elevation_4dp),
findViewById(R.id.elevation_8dp),
findViewById(R.id.elevation_16dp)
};
float[] elevations = {2f, 4f, 8f, 16f};
for (int i = 0; i < elevatedViews.length; i++) {
View view = elevatedViews[i];
float elevation = elevations[i];
// Create elevated background
MaterialShapeDrawable background = MaterialShapeDrawable.createWithElevationOverlay(this, elevation);
background.setShapeAppearanceModel(ShapeAppearanceModel.builder()
.setAllCorners(CornerFamily.ROUNDED, 8f)
.build());
view.setBackground(background);
view.setElevation(elevation);
// Add elevation text
TextView elevationText = view.findViewById(R.id.elevation_text);
if (elevationText != null) {
elevationText.setText(String.format("%.0fdp", elevation));
}
}
// Animated elevation change
MaterialButton elevationButton = findViewById(R.id.elevation_button);
elevationButton.setOnClickListener(v -> animateElevation(v));
}
private void animateElevation(View view) {
float startElevation = view.getElevation();
float endElevation = startElevation == 2f ? 16f : 2f;
ValueAnimator elevationAnimator = ValueAnimator.ofFloat(startElevation, endElevation);
elevationAnimator.setDuration(300);
elevationAnimator.addUpdateListener(animation -> {
float elevation = (float) animation.getAnimatedValue();
view.setElevation(elevation);
// Update background overlay
ElevationOverlayProvider provider = new ElevationOverlayProvider(this);
int overlayColor = provider.compositeOverlayWithThemeSurfaceColorIfNeeded(elevation);
view.setBackgroundColor(overlayColor);
});
elevationAnimator.start();
}
// Theme switching example
private void switchToCustomTheme() {
// Save current theme preference
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit().putString("theme", "custom").apply();
// Recreate activity to apply new theme
recreate();
}
}
// Application class for global theming setup
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Enable dynamic colors globally
DynamicColors.applyToActivitiesIfAvailable(this, new DynamicColorsOptions.Builder()
.setOnAppliedCallback(options -> {
Log.d("DynamicColors", "Dynamic colors applied successfully");
})
.setPrecondition((activity, theme) -> {
// Only apply to certain activities or themes
return !activity.getClass().getSimpleName().equals("SplashActivity");
})
.build());
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-google-android-material--material