可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am using Android v21 support library.
I have created a button with custom background color. The Material design effects like ripple, reveal are gone (except the elevation on click) when I use the back ground color.
<Button
style="?android:attr/buttonStyleSmall"
android:background="?attr/colorPrimary"
android:textColor="@color/white"
android:textAllCaps="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button1"
/>
The following is a normal button and the effects are working just fine.
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:text="Button1"
/>
回答1:
When you use android:background
, you are replacing much of the styling and look and feel of a button with a blank color.
Update: As of the version 23.0.0 release of AppCompat, there is a new Widget.AppCompat.Button.Colored
style which uses your theme's colorButtonNormal
for the disabled color and colorAccent
for the enabled color.
This allows you apply it to your button directly via
<Button
...
style="@style/Widget.AppCompat.Button.Colored" />
If you need a custom colorButtonNormal
or colorAccent
, you can use a ThemeOverlay
as explained in this pro-tip and android:theme
on the button.
Previous Answer
You can use a drawable in your v21 directory for your background such as:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:drawable="?attr/colorPrimary"/>
</ripple>
This will ensure your background color is ?attr/colorPrimary
and has the default ripple animation using the default ?attr/colorControlHighlight
(which you can also set in your theme if you'd like).
Note: you'll have to create a custom selector for less than v21:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/primaryPressed" android:state_pressed="true"/>
<item android:drawable="@color/primaryFocused" android:state_focused="true"/>
<item android:drawable="@color/primary"/>
</selector>
Assuming you have some colors you'd like for the default, pressed, and focused state. Personally, I took a screenshot of a ripple midway through being selected and pulled the primary/focused state out of that.
回答2:
There is another simple solution to provide custom background for "Flat" buttons while keeping their "Material" effects.
- Place your button in ViewGroup with desired background set there
- set selectableItemBackground from current theme as background for your button (API >=11)
i.e. :
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/blue">
<Button
style="?android:attr/buttonStyleSmall"
android:background="?android:attr/selectableItemBackground"
android:textColor="@android:color/white"
android:textAllCaps="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button1"
/>
</FrameLayout>
Can be used for Flat buttons, it works on API >=11, and you will get ripple effect on >=21 devices, keeping regular buttons on pre-21 till AppCompat is updated to support ripple there as well.
You can also use selectableItemBackgroundBorderless for >=21 buttons only.
回答3:
Here is a simple and backward compatible way to deliver ripple effect to raised buttons with the custom background.
Your layout should look like this
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/my_custom_background"
android:foreground="?android:attr/selectableItemBackground"/>
回答4:
I ran into this problem today actually playing with the v22 library.
Assuming that you're using styles you can set the colorButtonNormal
property and the buttons will use that color by default.
<style name="AppTheme" parent="BaseTheme">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/primaryColor</item>
<item name="colorPrimaryDark">@color/primaryColorDark</item>
<item name="colorAccent">@color/accentColor</item>
<item name="colorButtonNormal">@color/primaryColor</item>
</style>
Outside of that you could still make a style for the button then use that per button if you needed an assortment of colors (haven't tested, just speculating).
Remember to add android:
before the item names in your v21 style.
回答5:
With AppCompat (22.1.1+) you can add a style like this:
<style name="MyGreenButton">
<item name="colorButtonNormal">#009900</item>
</style>
And use it by just applying the style:
<android.support.v7.widget.AppCompatButton
style="@style/MyGreenButton"
android:layout_width="match_width"
android:layout_height="wrap_content"
android:text="A Green Button"
/>
Programmatically changing the color, I found that the only way to update the color (on API 15 or 16) was to use the 'background tint list' instead. And it doesn't remove the nice radial animation on API 21 devices:
ColorStateList colorStateList = new ColorStateList(new int[][] {{0}}, new int[] {0xFF009900}); // 0xAARRGGBB
button.setSupportBackgroundTintList(colorStateList);
Because button.setBackground(...)
and button.getBackground().mutate().setColorFilter(...)
do not change the button color on API 15 and 16 like they do on API 21.
回答6:
The @ianhanniballake's answer is absolutely correct and simple. But it took me few days to understand. For someone who don't understand his answer, here is more detail implementation
<Button
android:id="@+id/btn"
style="@style/MaterialButton"
... />
<style name="MaterialButton" parent="Widget.AppCompat.Button.Colored">
<item name="android:theme">@style/Theme.MaterialButton</item>
...
</style>
<style name="Theme.MaterialButton" parent="YourTheme">
<item name="colorAccent">@color/yourAccentColor</item>
<item name="colorButtonNormal">@color/yourButtonNormalColor</item>
</style>
===Or===
<Button
android:id="@+id/btn"
style="@style/Widget.AppCompat.Button.Colored"
android:theme="@style/Theme.MaterialButton" />
<style name="Theme.MaterialButton" parent="YourTheme">
<item name="colorAccent">@color/yourAccentColor</item>
<item name="colorButtonNormal">@color/yourButtonNormalColor</item>
</style>
回答7:
I used the backgroundTint and foreground:
<Button
android:layout_width="match_parent"
android:layout_height="40dp"
android:backgroundTint="@color/colorAccent"
android:foreground="?android:attr/selectableItemBackground"
android:textColor="@android:color/white"
android:textSize="10sp"/>
回答8:
I came to this post looking for a way to have a background color of my ListView
Item, yet keep the ripple.
I simply added my color as a background and the selectableItemBackground as a foreground:
<style name="my_list_item">
<item name="android:background">@color/white</item>
<item name="android:foreground">?attr/selectableItemBackground</item>
<item name="android:layout_height">@dimen/my_list_item_height</item>
</style>
and it works like a charm. I guess the same technique could be used for buttons as well. Good luck :)
回答9:
Use backgroundTint
instead of background
回答10:
If you are interested in ImageButton you can try this simple thing :
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_button"
android:background="?attr/selectableItemBackgroundBorderless"
/>
回答11:
v22.1
of appcompat-v7
introduced some new possibilities. Now it's possible to assign a specific theme only to one view.
Deprecated use of app:theme for styling Toolbar. You can now use
android:theme for toolbars on all API level 7 and higher devices and
android:theme support for all widgets on API level 11 and higher
devices.
So instead of setting the desired color in a global theme, we create a new one and assign it only to the Button
Example:
<style name="MyColorButton" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorButtonNormal">@color/myColor</item>
</style>
And use this style as theme of your Button
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button1"
android:theme="@style/MyColorButton"/>
回答12:
If you're ok with using a third party library, check out traex/RippleEffect. It allows you to add a Ripple effect to ANY view with just a few lines of code. You just need to wrap, in your xml layout file, the element you want to have a ripple effect with a com.andexert.library.RippleView
container.
As an added bonus it requires Min SDK 9 so you can have design consistency across OS versions.
Here's an example taken from the libraries' GitHub repo:
<com.andexert.library.RippleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:rv_centered="true">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@android:drawable/ic_menu_edit"
android:background="@android:color/holo_blue_dark"/>
</com.andexert.library.RippleView>
You can change the ripple colour by adding this attribute the the RippleView element: app:rv_color="@color/my_fancy_ripple_color
回答13:
<android.support.v7.widget.AppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:backgroundTint="#fff"
android:textColor="#000"
android:text="test"/>
Use
xmlns:app="http://schemas.android.com/apk/res-auto"
and the color will acept on pre-lolipop
回答14:
There are two approaches explained in the great tutorial be Alex Lockwood: http://www.androiddesignpatterns.com/2016/08/coloring-buttons-with-themeoverlays-background-tints.html:
Approach #1: Modifying the button’s background color w/ a ThemeOverlay
<!-- res/values/themes.xml -->
<style name="RedButtonLightTheme" parent="ThemeOverlay.AppCompat.Light">
<item name="colorAccent">@color/googred500</item>
</style>
<Button
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="@style/RedButtonLightTheme"/>
Approach #2: Setting the AppCompatButton’s background tint
<!-- res/color/btn_colored_background_tint.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Disabled state. -->
<item android:state_enabled="false"
android:color="?attr/colorButtonNormal"
android:alpha="?android:attr/disabledAlpha"/>
<!-- Enabled state. -->
<item android:color="?attr/colorAccent"/>
</selector>
<android.support.v7.widget.AppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:backgroundTint="@color/btn_colored_background_tint"/>
回答15:
Programmatically applying the colors:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
ColorStateList colorStateListRipple = new ColorStateList(
new int[][] {{0}},
new int[] {Color.WHITE} // ripple color
);
RippleDrawable rippleDrawable = (RippleDrawable) myButton.getBackground();
rippleDrawable.setColor(colorStateListRipple);
myButton.setBackground(rippleDrawable); // applying the ripple color
}
ColorStateList colorStateList = new ColorStateList(
new int[][]{
new int[]{android.R.attr.state_pressed}, // when pressed
new int[]{android.R.attr.state_enabled}, // normal state color
new int[]{} // normal state color
},
new int[]{
Color.CYAN, // when pressed
Color.RED, // normal state color
Color.RED // normal state color
}
);
ViewCompat.setBackgroundTintList(myButton, colorStateList); // applying the state colors
回答16:
I tried this:
android:backgroundTint:"@color/mycolor"
instead of changing background property.
This does not remove the material effect.