Widget.AppCompat.Button确保了所有Button默认情况下看起来大致相同。但是这些特性例如按钮背景色在Light和Dark主题下又是如何被取决的,又或者是诸如disabled, pressed, and focused等状态下的情况呢?对于这些,AppCompat主要取决于以下三种不同的属性(theme attributes):
R.attr.colorButtonNormal:决定按钮在普通状态 normal state下的背景色, light themes主题下为#ffd6d7d7,dark themes主题下为#ff5a595b。
/** * Utility class for creating background tint {@link ColorStateList}s. */ public final class BackgroundTints { private static final int[] DISABLED_STATE_SET = new int[]{-android.R.attr.state_enabled}; private static final int[] PRESSED_STATE_SET = new int[]{android.R.attr.state_pressed}; private static final int[] FOCUSED_STATE_SET = new int[]{android.R.attr.state_focused}; private static final int[] EMPTY_STATE_SET = new int[0];
/** * Returns a {@link ColorStateList} that can be used as a colored button's background tint. * Note that this code makes use of the {@code android.support.v4.graphics.ColorUtils} * utility class. */ public static ColorStateList forColoredButton(Context context, @ColorInt int backgroundColor) { // On pre-Lollipop devices, we need 4 states total (disabled, pressed, focused, and default). // On post-Lollipop devices, we need 2 states total (disabled and default). The button's // RippleDrawable will animate the pressed and focused state changes for us automatically. final int numStates = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? 4 : 2;
final int[][] states = new int[numStates][]; final int[] colors = new int[numStates];
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { final int highlightedBackgroundColor = getHighlightedBackgroundColor(context, backgroundColor);
/** * Returns the theme-dependent ARGB background color to use for disabled buttons. */ @ColorInt private static int getDisabledButtonBackgroundColor(Context context) { // Extract the disabled alpha to apply to the button using the context's theme. // (0.26f for light themes and 0.30f for dark themes). final TypedValue tv = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, tv, true); final float disabledAlpha = tv.getFloat();
// Use the disabled alpha factor and the button's default normal color // to generate the button's disabled background color. final int colorButtonNormal = getThemeAttrColor(context, R.attr.colorButtonNormal); final int originalAlpha = Color.alpha(colorButtonNormal); return ColorUtils.setAlphaComponent( colorButtonNormal, Math.round(originalAlpha * disabledAlpha)); }
/** * Returns the theme-dependent ARGB color that results when colorControlHighlight is drawn * on top of the provided background color. */ @ColorInt private static int getHighlightedBackgroundColor(Context context, @ColorInt int backgroundColor) { final int colorControlHighlight = getThemeAttrColor(context, R.attr.colorControlHighlight); return ColorUtils.compositeColors(colorControlHighlight, backgroundColor); }
/** Returns the theme-dependent ARGB color associated with the provided theme attribute. */ @ColorInt private static int getThemeAttrColor(Context context, @AttrRes int attr) { final TypedArray array = context.obtainStyledAttributes(null, new int[]{attr}); try { return array.getColor(0, 0); } finally { array.recycle(); } }