Commit e66bc5de authored by newt's avatar newt Committed by Commit bot

Add ButtonCompat: a Material-styled button on all versions of Android.

This adds a new widget, ButtonCompat, which is a Material-styled button.
On pre-L devices, the widget approximates the Material style, but
doesn't have ripples or shadows. The color of ButtonCompat can be easily
changed using setButtonColor().

This also adds a style ButtomBorderlessCompat than can be applied to
Buttons to make them look like borderless Material buttons.

BUG=442690

Review URL: https://codereview.chromium.org/902893004

Cr-Commit-Position: refs/heads/master@{#314942}
parent fea7dfa8
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:id="@android:id/mask"
android:drawable="@drawable/button_compat_shape" />
</ripple>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:drawable="@drawable/button_compat_shape" />
</ripple>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#fff" />
<corners android:radius="2dp" />
</shape>
...@@ -197,4 +197,25 @@ ...@@ -197,4 +197,25 @@
<item name="android:windowEnterAnimation">@anim/fullscreen_notification_in</item> <item name="android:windowEnterAnimation">@anim/fullscreen_notification_in</item>
</style> </style>
<!-- Buttons -->
<style name="ButtonCompatBase">
<item name="android:minWidth">88dp</item>
<item name="android:minHeight">36dp</item>
<item name="android:textSize">14sp</item>
<item name="android:paddingStart">20dp</item>
<item name="android:paddingEnd">20dp</item>
<item name="android:paddingTop">5dp</item>
<item name="android:paddingBottom">5dp</item>
<item name="android:textAllCaps">true</item>
<item name="android:focusable">true</item>
<item name="android:clickable">true</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
<style name="ButtonCompat" parent="ButtonCompatBase">
<item name="android:background">@drawable/button_compat_shape</item>
</style>
<style name="ButtonBorderlessCompat" parent="ButtonCompat">
<item name="android:background">?attr/selectableItemBackground</item>
</style>
</resources> </resources>
...@@ -55,4 +55,13 @@ ...@@ -55,4 +55,13 @@
</style> </style>
<style name="PreferenceLayout" parent="PreferenceLayoutBase" /> <style name="PreferenceLayout" parent="PreferenceLayoutBase" />
<!-- Buttons -->
<style name="ButtonCompat" parent="ButtonCompatBase">
<item name="android:background">@drawable/button_compat</item>
<item name="android:fontFamily">sans-serif-medium</item>
</style>
<style name="ButtonBorderlessCompat" parent="ButtonCompat">
<item name="android:background">@drawable/button_borderless_compat</item>
</style>
</resources> </resources>
...@@ -30,4 +30,9 @@ ...@@ -30,4 +30,9 @@
<!-- The hint to display in the floating label --> <!-- The hint to display in the floating label -->
<attr name="floatLabelHint" format="reference|string" /> <attr name="floatLabelHint" format="reference|string" />
</declare-styleable> </declare-styleable>
<declare-styleable name="ButtonCompat">
<attr name="buttonColor" format="reference|color"/>
</declare-styleable>
</resources> </resources>
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.widget;
import android.animation.AnimatorInflater;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.widget.Button;
import org.chromium.chrome.R;
/**
* A Material-styled button with a customizable background color.
*
* Create a button in Java:
*
* new ButtonCompat(context, Color.RED);
*
* Create a button in XML:
*
* <ButtonCompat
* android:layout_width="wrap_content"
* android:layout_height="wrap_content"
* android:text="Click me"
* chrome:buttonColor="#f00" />
*
* On L devices, this is a true Material button. On earlier devices, the button is similar but lacks
* ripples and lacks a shadow when pressed.
*/
public class ButtonCompat extends Button {
/** The amount by which to dim the button background when pressed. */
private static final float PRE_L_DIM_AMOUNT = 0.85f;
private int mColor;
/**
* Constructs a button with the given buttonColor as its background.
*/
public ButtonCompat(Context context, int buttonColor) {
this(context, buttonColor, null);
}
/**
* Constructor for inflating from XML.
*/
public ButtonCompat(Context context, AttributeSet attrs) {
this(context, getColorFromAttributeSet(context, attrs), attrs);
}
private ButtonCompat(Context context, int buttonColor, AttributeSet attrs) {
// To apply the ButtonCompat style to this view, use a ContextThemeWrapper to inject the
// ButtonCompat style into the current theme, and pass 0 as the defStyleAttr to the super
// constructor to prevent the default Button style from being applied.
super(new ContextThemeWrapper(context, R.style.ButtonCompat), attrs, 0);
getBackground().mutate();
setButtonColor(buttonColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Use the StateListAnimator from the Widget.Material.Button style to animate the
// elevation when the button is pressed.
TypedArray a = getContext().obtainStyledAttributes(null,
new int[]{android.R.attr.stateListAnimator}, 0,
android.R.style.Widget_Material_Button);
setStateListAnimator(AnimatorInflater.loadStateListAnimator(getContext(),
a.getResourceId(0, 0)));
a.recycle();
}
}
/**
* Sets the background color of the button.
*/
public void setButtonColor(int color) {
mColor = color;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getBackground().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
} else {
updateButtonBackgroundPreL();
}
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
updateButtonBackgroundPreL();
}
}
private void updateButtonBackgroundPreL() {
int color = mColor;
for (int state : getDrawableState()) {
if (state == android.R.attr.state_pressed
|| state == android.R.attr.state_focused
|| state == android.R.attr.state_selected) {
color = getActiveColorPreL();
break;
}
}
GradientDrawable background = (GradientDrawable) getBackground();
background.setColor(color);
}
private int getActiveColorPreL() {
return Color.rgb(
Math.round(Color.red(mColor) * PRE_L_DIM_AMOUNT),
Math.round(Color.green(mColor) * PRE_L_DIM_AMOUNT),
Math.round(Color.blue(mColor) * PRE_L_DIM_AMOUNT)
);
}
private static int getColorFromAttributeSet(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ButtonCompat, 0, 0);
int color = a.getColor(R.styleable.ButtonCompat_buttonColor, Color.WHITE);
a.recycle();
return color;
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment