以编程方式将样式应用于 MaterialButton
Apply Style to MaterialButton programmatically
我正在尝试创建一个扩展自 MaterialButton
的自定义视图并在代码中应用样式,因此我不需要在 xml 中执行此操作。
class CustomRedButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : MaterialButton(ContextThemeWrapper(context, R.style.ButtonRedStyle), attrs, defStyleAttr)
风格是:
<style name="ButtonRedStyle"
parent="Widget.MaterialComponents.Button.TextButton">
<item name="backgroundTint">@color/red</item>
<item name="rippleColor">@color/grey</item>
<item name="strokeWidth">1dp</item>
<item name="strokeColor">@color/black</item>
</style>
一切正常,但 backgroundTint
属性。由于某种原因,背景颜色没有改变,它具有主题的原色。但是,如果我尝试将样式应用于 xml 中的 MaterialButton
,它确实会改变颜色。
知道为什么会发生这种情况或如何实现吗?
如果你想改变 CustomView
的样式,你必须将它传递给构造函数,方法是将它传递给第三个参数 defStyleAttr
像这样:
class CustomRedButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.style.ButtonRedStyle // Just default style like this
) : MaterialButton(context, attrs, defStyleAttr)
您可以像这样以编程方式初始化它,
CustomRedButton(this, null, R.style.ButtonRedStyle) // Initialization, ('this' is context)
有关详细信息,请参阅 here
我也遇到了同样的问题。到目前为止我发现的唯一解决方法是以编程方式设置色调,如:
button.setBackgroundTintList(ColorStateList.valueOf(Color.RED));
对于 TextButton
不应该有背景(只是文本有颜色)。对于彩色按钮,您应该使用默认的 Filled Button 样式,即 Widget.MaterialComponents.Button
.
当作为主题应用时,按钮使用不同的属性。它在 主题属性映射 部分中进行了描述:https://material.io/develop/android/components/material-button/
Filled button
+------------------------+-----------------------------------------+
| Component Attribute | Default Theme Attribute Value |
+------------------------+-----------------------------------------+
| android:textAppearance | textAppearanceButton |
| android:textColor | colorOnPrimary |
| iconTint | colorOnPrimary |
| rippleColor | colorOnPrimary at 32% opacity (pressed) |
| iconTint | colorOnPrimary |
| backgroundTint | colorPrimary |
| ... | ... |
+------------------------+-----------------------------------------+
在您的情况下,主题应该类似于:
<style name="ButtonRedTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/red</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorOnSurface">@color/black</item>
</style>
您还可以使用
将所有按钮更改为特定样式
<item name="materialButtonStyle">@style/ButtonRedTheme</item>
在您的应用主题中。
正在使用
MaterialButton(ContextThemeWrapper(context, R.style.ButtonRedStyle), attrs, defStyleAttr)
您正在对默认样式应用 themeoverlay,您未应用不同的样式。
意思是:
<style name="ButtonRedTheme" parent="...">
<item name="colorPrimary">@color/...</item>
<item name="colorOnPrimary">@color/...</item>
<item name="colorSecondary">@color/...</item>
</style>
如果您想应用不同的样式,您必须:
- 在
attrs.xml
中定义自定义属性
<attr name="myButtonStyle" format="reference"/>
- 在您的应用主题中为该属性指定样式:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
<item name="myButtonStyle">@style/CustomButtonStyle</item>
</style>
- 定义自定义样式:
<style name="CustomButtonStyle" parent="Widget.MaterialComponents.Button.*">
<item name="backgroundTint">@color/...</item>
<item name="rippleColor">@color/grey</item>
<item name="strokeWidth">1dp</item>
<item name="strokeColor">@color/black</item>
</style>
最后使用:
val customButton = MaterialButton(context, null, R.attr.myButtonStyle)
对于一个简单的用例,我遇到了同样的问题,我需要更新按钮 backgroundTint
和 isEnabled
状态
我做了什么:
我创建了一个从 MaterialButton
扩展的自定义 class
class MyCustomMaterialButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : MaterialButton(context, attrs)
然后我为此 class 添加了一个扩展来更新按钮样式属性:
fun MyCustomMaterialButton.updateEnabledState(enabled: Boolean){
apply {
if(enabled){
isEnabled = true
setBackgroundColor(ContextCompat.getColor(context, R.color.primary))
}
else{
isEnabled = false
setBackgroundColor(ContextCompat.getColor(context, R.color.primary_warm_grey_five))
}
}
}
这是 Xml 中的样子:
<com.karny.branding.KarnyMaterialButton
android:id="@+id/smsAuthButton"
style="@style/PrimaryButtonDisabled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="94dp"
android:layout_marginBottom="24dp"
android:text="@string/sms_auth_check"
app:layout_constraintEnd_toStartOf="@+id/left_middle_guide_line"
app:layout_constraintStart_toEndOf="@+id/right_middle_guide_line"
app:layout_constraintTop_toBottomOf="@+id/smsAuthNumberContainer" />
我正在尝试创建一个扩展自 MaterialButton
的自定义视图并在代码中应用样式,因此我不需要在 xml 中执行此操作。
class CustomRedButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : MaterialButton(ContextThemeWrapper(context, R.style.ButtonRedStyle), attrs, defStyleAttr)
风格是:
<style name="ButtonRedStyle"
parent="Widget.MaterialComponents.Button.TextButton">
<item name="backgroundTint">@color/red</item>
<item name="rippleColor">@color/grey</item>
<item name="strokeWidth">1dp</item>
<item name="strokeColor">@color/black</item>
</style>
一切正常,但 backgroundTint
属性。由于某种原因,背景颜色没有改变,它具有主题的原色。但是,如果我尝试将样式应用于 xml 中的 MaterialButton
,它确实会改变颜色。
知道为什么会发生这种情况或如何实现吗?
如果你想改变 CustomView
的样式,你必须将它传递给构造函数,方法是将它传递给第三个参数 defStyleAttr
像这样:
class CustomRedButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.style.ButtonRedStyle // Just default style like this
) : MaterialButton(context, attrs, defStyleAttr)
您可以像这样以编程方式初始化它,
CustomRedButton(this, null, R.style.ButtonRedStyle) // Initialization, ('this' is context)
有关详细信息,请参阅 here
我也遇到了同样的问题。到目前为止我发现的唯一解决方法是以编程方式设置色调,如:
button.setBackgroundTintList(ColorStateList.valueOf(Color.RED));
对于 TextButton
不应该有背景(只是文本有颜色)。对于彩色按钮,您应该使用默认的 Filled Button 样式,即 Widget.MaterialComponents.Button
.
当作为主题应用时,按钮使用不同的属性。它在 主题属性映射 部分中进行了描述:https://material.io/develop/android/components/material-button/
Filled button
+------------------------+-----------------------------------------+
| Component Attribute | Default Theme Attribute Value |
+------------------------+-----------------------------------------+
| android:textAppearance | textAppearanceButton |
| android:textColor | colorOnPrimary |
| iconTint | colorOnPrimary |
| rippleColor | colorOnPrimary at 32% opacity (pressed) |
| iconTint | colorOnPrimary |
| backgroundTint | colorPrimary |
| ... | ... |
+------------------------+-----------------------------------------+
在您的情况下,主题应该类似于:
<style name="ButtonRedTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/red</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorOnSurface">@color/black</item>
</style>
您还可以使用
将所有按钮更改为特定样式<item name="materialButtonStyle">@style/ButtonRedTheme</item>
在您的应用主题中。
正在使用
MaterialButton(ContextThemeWrapper(context, R.style.ButtonRedStyle), attrs, defStyleAttr)
您正在对默认样式应用 themeoverlay,您未应用不同的样式。
意思是:
<style name="ButtonRedTheme" parent="...">
<item name="colorPrimary">@color/...</item>
<item name="colorOnPrimary">@color/...</item>
<item name="colorSecondary">@color/...</item>
</style>
如果您想应用不同的样式,您必须:
- 在
attrs.xml
中定义自定义属性
<attr name="myButtonStyle" format="reference"/>
- 在您的应用主题中为该属性指定样式:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
<item name="myButtonStyle">@style/CustomButtonStyle</item>
</style>
- 定义自定义样式:
<style name="CustomButtonStyle" parent="Widget.MaterialComponents.Button.*">
<item name="backgroundTint">@color/...</item>
<item name="rippleColor">@color/grey</item>
<item name="strokeWidth">1dp</item>
<item name="strokeColor">@color/black</item>
</style>
最后使用:
val customButton = MaterialButton(context, null, R.attr.myButtonStyle)
对于一个简单的用例,我遇到了同样的问题,我需要更新按钮 backgroundTint
和 isEnabled
状态
我做了什么:
我创建了一个从 MaterialButton
class MyCustomMaterialButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : MaterialButton(context, attrs)
然后我为此 class 添加了一个扩展来更新按钮样式属性:
fun MyCustomMaterialButton.updateEnabledState(enabled: Boolean){
apply {
if(enabled){
isEnabled = true
setBackgroundColor(ContextCompat.getColor(context, R.color.primary))
}
else{
isEnabled = false
setBackgroundColor(ContextCompat.getColor(context, R.color.primary_warm_grey_five))
}
}
}
这是 Xml 中的样子:
<com.karny.branding.KarnyMaterialButton
android:id="@+id/smsAuthButton"
style="@style/PrimaryButtonDisabled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="94dp"
android:layout_marginBottom="24dp"
android:text="@string/sms_auth_check"
app:layout_constraintEnd_toStartOf="@+id/left_middle_guide_line"
app:layout_constraintStart_toEndOf="@+id/right_middle_guide_line"
app:layout_constraintTop_toBottomOf="@+id/smsAuthNumberContainer" />