在视图中定义样式和自定义属性而不是 xml

Define style and custom attribute in View instead of xml

我想为视图实现自定义样式。让我们以按钮为例。一些通用值将在应用程序中共享,因为我使用如下样式:

<style name="Widget.Demo.Button.Primary" parent="@style/Widget.MaterialComponents.Button">
        <item name="fontFamily">@font/roboto</item>
        <item name="android:fontFamily">@font/roboto</item>
        <item name="android:minHeight">64dp</item>
        <item name="android:theme">@style/ThemeOverlay.Demo.GrayPrimary</item>
</style>

<style name="ThemeOverlay.Demo.GrayPrimary" parent="">
    <item name="colorPrimary">@color/gray</item>
</style>

现在我想在按钮中添加一些自定义属性,如下所示(这只是一个示例,不是真正的属性):

     <com.android.CustomButton
        android:id="@+id/btn_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/first"
        app:abc="primary"
        style="@style/Widget.Demo.Button.Primary"/>

attrs.xml:

<declare-styleable name="CustomButtonAttr" >
        <attr name="abc" format="enum" >
            <enum name="primary" value="1"/>
            <enum name="secondary" value="2"/>
    </declare-styleable>

我不想每次都在 xml 中定义样式和自定义属性。有什么方法可以直接在我的自定义视图中获取自定义属性,并在我下面的 class?

中默认设置 Widget.Demo.Button.Primary
class CustomButton : MaterialButton {
    constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(
        ThemeEnforcement.createThemedContext(context, attributeSet, 0, 0),
        attributeSet,
       0
    )
}

我不想在 xml 中为我创建的每个按钮或视图定义样式。那么有没有办法在 CustomButton class 中定义自定义属性?如果可以请给我一些参考。

提前致谢。

是的,您可以在构造函数中使用默认样式属性。

定义新属性:

<attr name="customButtonStyle" format="reference" />

然后使用合适的视图构造函数:

private val defStyleAttr = R.attr.customButtonStyle

class CustomButton(context: Context, attrs: AttributeSet) : MaterialButton(
    ThemeEnforcement.createThemedContext(context, attributeSet, defStyleAttr, 0),
    attributeSet,
    defStyleAttr
) {

    init {
        val typedArray = context.obtainStyledAttributes(
            attrs,
            R.styleable.CustomButton, 
            defStyleAttr,
            0
        )
        ...
    
}

在您的主题中,将 customButtonStyle 指向您希望默认使用的样式资源:

<style name="Theme.Demo" parent="Base.Theme.Demo">
    <item name="customButtonStyle">@style/Widget.Demo.Button.Primary</item>
</style>

请注意,该样式资源中的 android:theme 应更改为 materialThemeOverlay,因为从默认样式读取时不会应用它。由于您已经使用 ThemeEnforcement 函数包装了上下文(较新版本的 Material Design Components 将其更改为 MaterialThemeOverlay),此自定义视图支持 materialThemeOverlay


您也可以将自定义属性添加到样式中:

<style name="Widget.Demo.Button.Primary" parent="@style/Widget.MaterialComponents.Button">
    <item name="abc">primary</item>
    <item name="fontFamily">@font/roboto</item>
    <item name="android:fontFamily">@font/roboto</item>
    <item name="android:minHeight">64dp</item>
    <item name="materialThemeOverlay">@style/ThemeOverlay.Demo.GrayPrimary</item>
</style>

Reference (blog + video)