Android XML:自定义按钮可绘制,每个按钮状态不重复 xml?

Android XML: Custom button drawable without duplicate xml for each button state?

我正在尝试制作一个 custom_button,到目前为止我所拥有的是,两个状态(按下和启用)有自己的形状和边框:

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

    <!-- Pressed -->
    <item android:state_pressed='true'>
        <layer-list>
            <item> <!-- Border -->
                <shape
                    android:shape='rectangle'>

                    <solid android:color='@color/Foreground'/>
                </shape>
            </item>

            <item android:bottom='2dp' android:top='2dp' android:left='2dp' android:right='2dp'> <!-- Color -->
                <shape
                    android:shape='rectangle'>

                    <solid android:color='@color/WidgetSoft'/>
                </shape>
            </item>
        </layer-list>
    </item>

    <!-- Enabled -->
    <item>
        <layer-list>
            <item> <!-- Border -->
                <shape
                    android:shape='rectangle'>

                    <solid android:color='@color/Foreground'/>
                </shape>
            </item> <!-- Color -->

            <item android:bottom='2dp' android:top='2dp' android:left='2dp' android:right='2dp'> <!-- Base Color -->
                <shape
                    android:shape='rectangle'>

                    <solid android:color='@color/Widget'/>
                </shape>
            </item>
        </layer-list>
    </item>

</selector>

这有效,但它指定了两个相同的按钮,只是颜色不同。当我添加其他按钮状态和更多外观时,这会越来越重复。有没有一种方法可以让 base_button.xml 可绘制,其中可以设置每个按钮的基本相同属性和 custom_button.xml 在哪里可以在相应的标签中设置特定于按钮状态的属性?

下面是我的意思的伪示例,但我不知道如何使它成为现实。 custom_button.xml 处理按钮状态,base_button.xml 指定按钮的基本特征。

custom_button.xml:

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

    <!-- Pressed -->
    <item android:state_pressed='true' android:drawable='@drawable/base_button'>

        <!-- SET GLOBAL_BORDER_COLOR TO '@color/btnPressedBorder' -->
        <!-- SET GLOBAL_BASE_COLOR TO '@color/btnPressedBase' -->

    </item>

    <!-- Enabled -->
    <item  android:drawable='@drawable/base_button'>

        <!-- SET GLOBAL_BORDER_COLOR TO '@color/btnEnabledBorder' -->
        <!-- SET GLOBAL_BASE_COLOR TO '@color/btnEnabledBase' -->

    </item>
    
</selector>

base_button.xml:

<?xml version='1.0' encoding='utf-8'?>
<layer-list xmlns:android='http://schemas.android.com/apk/res/android'>
    <item>
        <shape
            android:shape='rectangle'>

            <solid android:color= GLOBAL_BORDER_COLOR />
        </shape>
    </item>

    <item android:bottom='2dp' android:top='2dp' android:left='2dp' android:right='2dp'>
        <shape
            android:shape='rectangle'>

            <solid android:color= GLOBAL_BASE_COLOR />
        </shape>
    </item>
</layer-list>

这在 XML 中甚至可能吗?我在网上遇到了 xsl:variable,但无法正常工作。非常感谢任何关于如何实现相同结果的建议或替代方法!

您可以使用 ColorStateList 作为颜色。为小部件的边框定义一个 ColorStateList,并为其填充定义一个。小部件的状态将被下推到 ColorStateList,其中将选择颜色。然后,您可以按如下方式定义可绘制对象:

base_button.xml

<layer-list>
    <item>
        <shape android:shape='rectangle'>
            <solid android:color="@color/widget_border" />
        </shape>
    </item>

    <item
        android:bottom='2dp'
        android:left='2dp'
        android:right='2dp'
        android:top='2dp'>
        <shape android:shape='rectangle'>
            <solid android:color="@color/widget_fill" />
        </shape>
    </item>
</layer-list>

ColorStateLists 看起来像这样。 (请原谅颜色选择。)

widget_fill.xml

<selector>
    <item android:color="@android:color/holo_red_light" android:state_pressed="true" />
    <item android:color="@android:color/holo_blue_light" android:state_enabled="true" />
</selector>

widget_border.xml

<selector>
    <item android:color="@android:color/black" android:state_pressed="true" />
    <item android:color="@android:color/holo_red_light" android:state_enabled="true" />
</selector>

最后,示例布局文件:

activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:background="@drawable/base_button"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

将所有内容放在一起,将如下所示: