在Android着色按钮与材料设计和AppCompat

在今天AppCompat更新出来之前,我能够改变Android L中按钮的颜色,但不能在旧版本上更改。在包含新的AppCompat更新后,我无法更改两个版本的颜色,当我尝试时,按钮就消失了。有人知道怎么改变按钮的颜色吗?

下面的图片展示了我想要达到的目标:

显示理想结果的图片

白色按钮是默认的,红色按钮是我想要的。

这是我之前为改变styles.xml中按钮的颜色所做的:

<item name="android:colorButtonNormal">insert color here</item>

要动态地进行:

button.getBackground().setColorFilter(getResources().getColor(insert color here), PorterDuff.Mode.MULTIPLY);

此外,我确实将主题父类从@android:style/Theme.Material.Light.DarkActionBar更改为Theme.AppCompat.Light.DarkActionBar

192839 次浏览

编辑(22.06.2016):

Appcompat库开始支持材料按钮后,我张贴了原始的响应。在这篇文章中你可以看到凸起和平面按钮的最简单实现。

最初的回答:

因为AppCompat还不支持按钮,你可以使用xml作为背景。为了做到这一点,我查看了Android的源代码,并找到了样式化材质按钮的相关文件。

1 -从源头看材料按钮的原始实现。

看看Btn_default_material.xml的android源代码

您可以将该文件复制到项目drawable-v21文件夹中。但是不要碰这里的颜色。您需要更改的文件是第二个文件。

drawable-v21 / custom_btn.xml

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:drawable="@drawable/btn_default_mtrl_shape" />
</ripple>

2 -获得原始材料按钮的形状

正如你意识到的,在这个可绘制对象中使用了一个形状,你可以在此文件的源代码中找到它。

<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="?attr/colorButtonNormal" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>

3 -获取材料按钮的尺寸

在这个文件中,你有一些从文件你可以在这里找到中使用的维度。你可以复制整个文件并放入你的文件夹中。这对于将相同的尺寸(用于材质按钮)应用到所有按钮是很重要的

4 -为旧版本创建另一个可绘制文件

对于旧版本,您应该有另一个具有相同名称的可绘制对象。我直接把项目内联而不是引用。你可能想要引用它们。但同样,最重要的是材质按钮的原始尺寸。

可拉的/ custom_btn.xml

    <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    

<!-- pressed state -->
<item android:state_pressed="true">
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="@color/PRESSED_STATE_COLOR" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
</inset>
</item>
    

<!-- focused state -->
<item android:state_focused="true">
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="@color/FOCUSED_STATE_COLOR" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
</inset>
</item>
    

<!-- normal state -->
<item>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="@color/NORMAL_STATE_COLOR" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
</inset>
</item>
</selector>

结果

你的按钮会在棒棒糖设备上产生连锁反应。旧版本将有完全相同的按钮,除了涟漪效应。但是因为你为不同的状态提供了可绘制对象,它们也会响应触摸事件(就像旧的方式一样)。

如果你只想要“平面”材质按钮,你可以使用selectableItemBackground属性自定义它们的背景,如在这里所述。

我刚刚创建了一个android库,它允许您轻松地修改按钮颜色和波纹颜色

https://github.com/xgc1986/RippleButton

<com.xgc1986.ripplebutton.widget.RippleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn"
android:text="Android button modified in layout"
android:textColor="@android:color/white"
app:buttonColor="@android:color/black"
app:rippleColor="@android:color/white"/>

你不需要为每个你想要不同颜色的按钮创建一个样式,允许你随机自定义颜色

在支持库rev.22中正式修复(2015年3月13日星期五)。参见相关谷歌代码问题:

https://issuetracker.google.com/issues/37008632

使用的例子

theme.xml:

<item name="colorButtonNormal">@color/button_color</item>

v21 / theme.xml

<item name="android:colorButtonNormal">@color/button_color</item>
在Android支持库22.1.0中,谷歌使Button色调可感知。 因此,另一种自定义按钮背景颜色的方法是使用backgroundTint属性

例如,

<Button
android:id="@+id/add_remove_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/bg_remove_btn_default"
android:textColor="@android:color/white"
tools:text="Remove" />

使用最新的支持库,你可以从AppCompatActivity继承你的活动,所以它会将你的Button膨胀为AppCompatButton,并让你有机会使用android:theme="@style/SomeButtonStyle"来样式布局中每个按钮的颜色,其中SomeButtonStyle是:

<style name="SomeButtonStyle" parent="@android:style/Widget.Button">
<item name="colorButtonNormal">@color/example_color</item>
</style>

我在2.3.7,4.4.1,5.0.2中工作过

实际上,我不想改变我的自定义按钮样式,但不幸的是,它们不再工作了。

我的应用程序有一个minSdkVersion 9和一切工作之前。

我不知道为什么,但自从我删除了android:在buttonStyle之前,它似乎又工作了

现在=工作中:

<item name="buttonStyle">@style/ButtonmyTime</item>

之前=只是灰色材质按钮:

<item name="android:buttonStyle">@style/ButtonmyTime</item>

我没有特殊的文件夹为新的android版本,因为我的按钮是相当平坦的,他们应该看起来在所有android版本相同。

也许有人能告诉我为什么我必须删除“android:” ImageButton仍然使用"android:"

<item name="android:imageButtonStyle">@style/ImageButtonmyTimeGreen</item>

这是我在android + 4.0中的appcompat-v7 . 22.2.0工作

在你的styles.xml中

<style name="Button.Tinted" parent="Widget.AppCompat.Button">
<item name="colorButtonNormal">YOUR_TINT_COLOR</item>
<item name="colorControlHighlight">@color/colorAccent</item>
<item name="android:textColor">@android:color/white</item>
</style>

在布局文件中

<Button
android:id="@+id/but_next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/but_continue"
android:theme="@style/Button.Tinted" />

在寻找答案2天后,按钮主题在API <中对我不起作用;21.

我唯一的解决方案是覆盖AppCompatButton着色不仅与基础应用主题“colorButtonNormal”,而且视图backgroundTint如下:

public class AppCompatColorButton extends AppCompatButton {


public AppCompatColorButton(Context context) {
this(context, null);
}


public AppCompatColorButton(Context context, AttributeSet attrs) {
this(context, attrs, android.support.v7.appcompat.R.attr.buttonStyle);
}


public AppCompatColorButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);


if (TintManager.SHOULD_BE_USED) {
setSupportBackgroundTintList(createButtonColorStateList(getContext(), attrs, defStyleAttr));
}
}


static final int[] DISABLED_STATE_SET = new int[]{-android.R.attr.state_enabled};
static final int[] FOCUSED_STATE_SET = new int[]{android.R.attr.state_focused};
static final int[] PRESSED_STATE_SET = new int[]{android.R.attr.state_pressed};
static final int[] EMPTY_STATE_SET = new int[0];


private ColorStateList createButtonColorStateList(Context context, AttributeSet attrs, int defStyleAttr) {
final int[][] states = new int[4][];
final int[] colors = new int[4];
int i = 0;


final int themeColorButtonNormal = ThemeUtils.getThemeAttrColor(context, android.support.v7.appcompat.R.attr.colorButtonNormal);
/*TypedArray a = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.backgroundTint }, defStyleAttr, 0);
final int colorButtonNormal = a.getColor(0, themeColorButtonNormal);*/
TypedArray a = context.obtainStyledAttributes(attrs, android.support.v7.appcompat.R.styleable.View, defStyleAttr, 0);
final int colorButtonNormal = a.getColor(android.support.v7.appcompat.R.styleable.View_backgroundTint, themeColorButtonNormal);
a.recycle();
final int colorControlHighlight = ThemeUtils.getThemeAttrColor(context, android.support.v7.appcompat.R.attr.colorControlHighlight);


// Disabled state
states[i] = DISABLED_STATE_SET;
colors[i] = ThemeUtils.getDisabledThemeAttrColor(context, android.support.v7.appcompat.R.attr.colorButtonNormal);
i++;


states[i] = PRESSED_STATE_SET;
colors[i] = ColorUtils.compositeColors(colorControlHighlight, colorButtonNormal);
i++;


states[i] = FOCUSED_STATE_SET;
colors[i] = ColorUtils.compositeColors(colorControlHighlight, colorButtonNormal);
i++;


// Default enabled state
states[i] = EMPTY_STATE_SET;
colors[i] = colorButtonNormal;
i++;


return new ColorStateList(states, colors);
}
}

然后你可以像这样定义你的按钮颜色:

<com.example.views.AppCompatColorButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#ffff0000"
app:backgroundTint="#ffff0000"
android:text="Button"
android:textColor="@android:color/white" />

更改单个按钮的颜色

ViewCompat.setBackgroundTintList(button, getResources().getColorStateList(R.color.colorId));
这已在AppCompat库的v23.0.0中得到增强 随着更多主题的加入,包括

Widget.AppCompat.Button.Colored

首先,包括appCompat依赖关系(如果还没有的话)

compile('com.android.support:appcompat-v7:23.0.0') {
exclude group: 'com.google.android', module: 'support-v4'
}

现在因为你需要使用compat的v23版本,你也需要针对SDK-v23 !

    compileSdkVersion = 23
targetSdkVersion = 23

在你的values/theme

<item name="android:buttonStyle">@style/BrandButtonStyle</item>

在你的values/style

<style name="BrandButtonStyle" parent="Widget.AppCompat.Button.Colored">
<item name="colorButtonNormal">@color/yourButtonColor</item>
<item name="android:textColor">@color/White</item>
</style>

在你的values-v21/style

<style name="BrandButtonStyle" parent="Widget.AppCompat.Button.Colored">
<item name="android:colorButtonNormal">@color/yourButtonColor</item>
<item name="android:textColor">@color/White</item>
</style>

由于您的按钮主题是基于Widget.AppCompat.Button.Colored,按钮上的文本颜色默认为白色!

但似乎有一个问题,当你禁用按钮,按钮将改变其颜色为浅灰色,但文本颜色将保持白色!

解决这个问题的方法是专门设置按钮上的文本颜色为白色!

现在你可以简单地定义你的按钮,让AppCompat做剩下的:)

<Button
android:layout_width="200dp"
android:layout_height="48dp" />
< p >禁用状态 禁用状态 < / p > < p >启用状态 Enabled State < / p >

编辑:

添加<Button android:theme="@style/BrandButtonStyle"/>

如果你想要下面的款式

enter image description here

添加此样式的按钮

style="@style/Widget.AppCompat.Button.Borderless.Colored"

如果你想要这种款式

enter image description here

添加以下代码

style="@style/Widget.AppCompat.Button.Colored"

对我来说,问题是在Android 5.0中android:colorButtonNormal没有效果,实际上,没有来自主题的项目(如android:colorAccent),但在Android 4.4.3中,例如,这样做。该项目配置了compileSdkVersiontargetSdkVersion到22,所以我已经按照@Muhammad Alfaifi的建议做了所有的更改,但最后,我注意到问题是buildToolsVersion,这没有更新。一旦我更改为23.0.1,一切都开始正常工作。现在,android:colorButtonNormal仍然没有效果,但至少按钮对android:colorAccent有反应,这对我来说是可以接受的。

我希望这个提示能帮助到一些人。 注意:我已经将样式直接应用于按钮,因为按钮的android:theme=[...]也没有效果
一种方法是让你只指向一个样式而不是主题,你的应用程序中的所有按钮都是一样的 在themes.xml中添加一个主题

    <style name="Theme.MyApp.Button.Primary.Blue" parent="Widget.AppCompat.Button">
<item name="colorButtonNormal">@color/someColor</item>
<item name="android:textColorPrimary">@android:color/white</item>
</style>

现在在styles.xml中添加

    <style name="MyApp.Button.Primary.Blue" parent="">
<item name="android:theme">@style/Theme.MyApp.Button.Primary.Blue</item>
</style>

现在在你的布局中,简单地指向按钮的样式

    <Button
...
style="@style/MyApp.Button.Primary.Blue"
...  />

要支持彩色按钮,请使用最新的AppCompat库(>23.2.1):

膨胀- XML

AppCompat部件:

android.support.v7.widget.AppCompatButton

AppCompat风格:

style="@style/Widget.AppCompat.Button.Colored"

要在xml中设置自定义颜色,请使用attr: app而不是android

(使用alt+enter或声明xmlns:app="http://schemas.android.com/apk/res-auto"来使用app)

应用程序: backgroundTint = " @color / your_custom_color”

例子:

<android.support.v7.widget.AppCompatButton
style="@style/Widget.AppCompat.Button.Colored"
app:backgroundTint="@color/your_custom_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Colored Button"/>

以编程方式设置它- JAVA

 ViewCompat.setBackgroundTintList(your_colored_button,
ContextCompat.getColorStateList(getContext(),R.color.your_custom_color));

答案是在主题 not style中

问题是Button的颜色与主题的colorButtonNormal一致。我尝试过很多不同的方法来改变风格,但都没有成功。所以我改变了按钮的主题

用colorButtonNormal和colorPrimary创建一个主题:

<style name="ThemeAwesomeButtonColor" parent="AppTheme">
<item name="colorPrimary">@color/awesomePrimaryColor</item>
<item name="colorButtonNormal">@color/awesomeButtonColor</item>
</style>

在按钮中使用此主题

<Button
android:id="@+id/btn_awesome"
style="@style/AppTheme.Button"
android:theme="@style/ThemeAwesomeButtonColor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/btn_awesome"/>

“AppTheme。按钮”可以是任何东西扩展按钮样式,就像这里我使用原色作为文本颜色:

<style name="AppTheme.Button" parent="Base.Widget.AppCompat.Button">
...
<item name="android:textColor">?attr/colorPrimary</item>
...
</style>

你可以得到你想要的任何颜色的按钮,与材料设计兼容。

更新

使用设计支持库(23.2.0)appcompatwidgets如下所示

In Android Support Library 22.1 .:

这是在膨胀布局-替换按钮时自动完成的 与appcompatextview, TextView与AppCompatTextView等确保 每个都可以支持着色。在这个版本中,那些色调意识 widget现在是公开可用的,允许您继续着色 支持,即使你需要子类化一个支持的小部件

色彩感知小部件的完整列表:

AppCompatAutoCompleteTextView
AppCompatButton
AppCompatCheckBox
AppCompatCheckedTextView
AppCompatEditText
AppCompatMultiAutoCompleteTextView
AppCompatRadioButton
AppCompatRatingBar
AppCompatSpinner
AppCompatTextView

预棒棒糖器件的材料设计:

AppCompat(又名ActionBarCompat)开始作为一个后端口 Android 4.0 ActionBar API用于运行在姜饼上的设备, 在反向移植实现的基础上提供一个公共API层 以及框架实现。AppCompat v21提供了一个API和 功能集是最新的Android 5.0


这个SO的回答帮助我得到了一个答案https://stackoverflow.com/a/30277424/3075340

我使用这个实用工具方法来设置按钮的背景色调。它适用于棒棒糖之前的设备:

// Set button background tint programmatically so it is compatible with pre-lollipop devices.
public static void setButtonBackgroundTintAppCompat(Button button, ColorStateList colorStateList){
Drawable d = button.getBackground();
if (button instanceof AppCompatButton) {
// appcompat button replaces tint of its drawable background
((AppCompatButton)button).setSupportBackgroundTintList(colorStateList);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Lollipop button replaces tint of its drawable background
// however it is not equal to d.setTintList(c)
button.setBackgroundTintList(colorStateList);
} else {
// this should only happen if
// * manually creating a Button instead of AppCompatButton
// * LayoutInflater did not translate a Button to AppCompatButton
d = DrawableCompat.wrap(d);
DrawableCompat.setTintList(d, colorStateList);
button.setBackgroundDrawable(d);
}


}

如何在代码中使用:

Utility.setButtonBackgroundTintAppCompat(myButton,
ContextCompat.getColorStateList(mContext, R.color.your_custom_color));

这样,如果你只是想改变背景色调,只是想保持漂亮的按钮效果,你就不必指定ColorStateList。

布局:

<android.support.v7.widget.AppCompatButton
style="@style/MyButton"
...
/>

styles.xml:

<style name="MyButton" parent="Widget.AppCompat.Button.Colored">
<item name="backgroundTint">@color/button_background_selector</item>
<item name="android:textColor">@color/button_text_selector</item>
</style>

颜色/ button_background_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#555555"/>
<item android:color="#00ff00"/>
</selector>

颜色/ button_text_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#888888"/>
<item android:color="#ffffff"/>
</selector>

对于那些使用ImageButton的人,下面是你如何做的:

在style.xml:

<style name="BlueImageButton" parent="Base.Widget.AppCompat.ImageButton">
<item name="colorButtonNormal">@color/primary</item>
<item name="android:tint">@color/white</item>
</style>

在v21 / style.xml:

<style name="BlueImageButton" parent="Widget.AppCompat.ImageButton">
<item name="android:colorButtonNormal">@color/primary</item>
<item name="android:tint">@color/white</item>
</style>

然后在布局文件中:

<android.support.v7.widget.AppCompatImageButton
android:id="@+id/my_button"
android:theme="@style/BlueImageButton"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_check_black_24dp"
/>

如果你使用带有colorButtonNormal的样式解决方案,不要忘记从Widget.AppCompat.Button.Colored继承,这样涟漪效应才会起作用;)

就像

<style name="CustomButtonStyle" parent="Widget.AppCompat.Button.Colored">
<item name="colorButtonNormal">@android:color/white</item>
</style>

如果你想使用AppCompat样式,如Widget.AppCompat.ButtonBase.Widget.AppCompat.Button.Colored等,你需要使用这些样式与支持库中的兼容视图。

下面的代码不适用于棒棒糖之前的设备:

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="@style/Widget.AppCompat.Button" />

你需要使用AppCompat按钮来启用AppCompat样式:

<android.support.v7.widget.AppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="@style/Widget.AppCompat.Button" />

另一个简单的解决方案是使用AppCompatButton

<android.support.v7.widget.AppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.AppCompat.Button.Colored"
app:backgroundTint="@color/red"
android:text="UNINSTALL" />

我在我的按钮主题中将android:textColor设置为@null,这很有帮助。

styles.xml

<style name="Button.Base.Borderless" parent="Widget.AppCompat.Button.Borderless.Colored">
<item name="android:textColor">@null</item>
</style>

some_layout.xml

<Button
style="@style/Button.Base.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hint" />

现在按钮文本的颜色是在AppTheme中定义的colorAccent

<style name="AppTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="colorAccent">@color/colorAccent</item>
<item name="borderlessButtonStyle">@style/Button.Base.Borderless</item>
<item name="alertDialogTheme">@style/AlertDialog</item>
</style>

我用这个。波纹效果和按钮点击阴影工作。

style.xml

<style name="Button.Red" parent="Widget.AppCompat.Button.Colored">
<item name="android:textColor">@color/material_white</item>
<item name="android:backgroundTint">@color/red</item>
</style>

布局按钮:

<Button
style="@style/Button.Red"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/close"/>

使用:

android:backgroundTint="@color/customColor"

甚至:

android:background="@color/customColor"

这将为按钮提供自定义颜色。

如果你想用任何颜色的代码来做这个:

DrawableCompat.setTintList(button.getBackground(), ColorStateList.valueOf(yourColor));
在我的情况下,而不是使用按钮,我使用androidx. appcompatt .widget. appcompatbutton