【问题标题】:Programmatically-inflated Button not accepting XML style以编程方式膨胀的按钮不接受 XML 样式
【发布时间】:2016-11-12 07:04:34
【问题描述】:

我正在尝试在整个应用程序中应用自定义按钮背景,但它似乎只有在我以编程方式执行时才有效。

这里是 styles.xml。我使用<item name="android:buttonStyle">@style/OverlayButton</item> 表示自定义样式“OverlayButton”(顺便说一下,<item name="buttonStyle">@style/OverlayButton</item> 给出“未找到与给定名称匹配的资源:attr 'buttonStyle'。”)然后<item name="android:background">@drawable/overlay_button</item> 调用自定义@987654324 @。

<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        <!-- http://stackoverflow.com/questions/6159113/android-where-is-the-spinner-widgets-text-color-attribute-hiding -->
        <item name="android:spinnerItemStyle">@style/SpinnerItem</item>
        <item name="android:spinnerDropDownItemStyle">@style/SpinnerItem.DropDownItem</item>
        <!-- http://stackoverflow.com/questions/8922924/how-to-change-android-spinner-popupbackground -->
        <!-- http://www.ezzylearning.com/tutorial.aspx?tid=1763429 -->
        <item name="android:listViewStyle">@style/myListView</item>
        <item name="android:buttonStyle">@style/OverlayButton</item>
    </style>

    <style name="SpinnerItem" parent="@android:style/Widget.TextView.SpinnerItem">
        <item name="android:textColor">#ADD8E6</item>
    </style>

    <style name="SpinnerItem.DropDownItem" parent="@android:style/Widget.DropDownItem.Spinner">
        <item name="android:textColor">#ADD8E6</item>
    </style>

    <style name="myListView" parent="@android:style/Widget.ListView">
        <item name="android:background">@drawable/intro_spinner</item>
    </style>

    <!-- Style for Overlay Buttons -->
    <style name="OverlayButton" parent="@android:style/Widget.Button">
        <item name="android:background">@drawable/overlay_button</item>
        <item name="android:gravity">center_vertical|center_horizontal</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textSize">12sp</item>
        <item name="android:textColor">#FF000000</item>
        <item name="android:layout_marginLeft">0dp</item>
        <item name="android:layout_marginRight">0dp</item>
        <item name="android:layout_marginTop">10dp</item>
        <item name="android:layout_marginBottom">10dp</item>
    </style>

    <!-- Style for Confirmation Dialog -->
    <style name="AlertDialogCustom" parent="@android:style/Theme.Dialog">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:background">@drawable/dialog_background</item>
        <item name="android:textColor">#FF000000</item>
        <item name="android:textSize">12sp</item>
        <item name="android:typeface">monospace</item>
    </style>

</resources>

自定义 Drawable overlay_button.xml 在这里。

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

    <item android:state_pressed="true" >
        <shape>
            <gradient
                android:startColor="#999999"
                android:endColor="#c0c0c0"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="#202619" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="1dp"
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp" />
            <margin
                android:left="5dp"
                android:top="5dp"
                android:right="5dp"
                android:bottom="5dp" />
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape>
            <gradient
                android:endColor="#999999"
                android:startColor="#c0c0c0"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="#202619" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="1dp"
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp" />
            <margin
                android:left="5dp"
                android:top="5dp"
                android:right="5dp"
                android:bottom="5dp" />
        </shape>
    </item>

    <item>        
        <shape>
            <gradient
                android:endColor="#aa393939"
                android:startColor="#aa737373"
                android:angle="270" />
            <stroke
                android:width="3dp"
                android:color="#202619" />
            <corners
                android:radius="3dp" />
            <padding
                android:left="1dp"
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp" />
            <margin
                android:left="5dp"
                android:top="5dp"
                android:right="5dp"
                android:bottom="5dp" />
        </shape>
    </item>
</selector>

当我使用final Button b = new Button(context); 创建一个按钮时,我没有得到自定义的 Drawable。但是,这有效:

final Button b = new Button(context);
Drawable buttonStates; // get Drawable to set button states
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    buttonStates = context.getResources().getDrawable(R.drawable.overlay_button, context.getTheme());
} else {
    buttonStates = context.getResources().getDrawable(R.drawable.overlay_button);
}
b.setBackground(buttonStates);

为什么这应该以编程方式而不是在 XML 中工作?

更新:@r-zagórski 有一个很好的线索。 XML-inflated 按钮采用自定义样式并按预期工作。不起作用的按钮以编程方式创建并通过LinearLayout.addView(b) 插入。 (顺便说一句,final Button b = new Button(context, null, R.drawable.overlay_button_selector) 不起作用。)我不明白为什么这不像 XML 膨胀按钮那样起作用。

【问题讨论】:

    标签: android android-button android-theme android-styles


    【解决方案1】:

    不幸的是,这不是正确定义有状态背景的方式。 正确的方法是为每个状态定义一个可绘制对象并使用“选择器”绑定它们。

    在您的情况下,在 res/drawable 文件夹中定义 3 个文件:

    overlay_button

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
       <item>
           <shape>
               <gradient
                   android:endColor="#aa393939"
                   android:startColor="#aa737373"
                   android:angle="270" />
               <stroke
                   android:width="3dp"
                   android:color="#202619" />
               <corners
                   android:radius="3dp" />
               <padding
                   android:left="1dp"
                   android:top="1dp"
                   android:right="1dp"
                   android:bottom="1dp" />
               <margin
                   android:left="5dp"
                   android:top="5dp"
                   android:right="5dp"
                   android:bottom="5dp" />
            </shape>
        </item>
    </layer-list>
    

    overlay_button_focused

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <shape>
                <gradient
                    android:endColor="#999999"
                    android:startColor="#c0c0c0"
                    android:angle="270" />
                <stroke
                    android:width="3dp"
                    android:color="#202619" />
                <corners
                    android:radius="3dp" />
                <padding
                    android:left="1dp"
                    android:top="1dp"
                    android:right="1dp"
                    android:bottom="1dp" />
                <margin
                    android:left="5dp"
                    android:top="5dp"
                    android:right="5dp"
                    android:bottom="5dp" />
            </shape>
        </item>
    </layer-list>
    

    overlay_button_pressed

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item >
            <shape>
                <gradient
                    android:startColor="#999999"
                    android:endColor="#c0c0c0"
                    android:angle="270" />
                <stroke
                    android:width="3dp"
                    android:color="#202619" />
                <corners
                    android:radius="3dp" />
                <padding
                    android:left="1dp"
                    android:top="1dp"
                    android:right="1dp"
                    android:bottom="1dp" />
                <margin
                    android:left="5dp"
                    android:top="5dp"
                    android:right="5dp"
                    android:bottom="5dp" />
            </shape>
        </item>
    </layer-list>
    

    选择器文件overlay_selector

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/overlay_button_focused" android:state_focused="true"/>
        <item android:drawable="@drawable/overlay_button_pressed" android:state_pressed="true"/>
        <item android:drawable="@drawable/overlay_button"/>
    </selector>
    

    还有styles.xml

    <style name="OverlayButton" parent="@android:style/Widget.Button">
        <item name="android:background">@drawable/overlay_selector</item>
        ....
    </style>
    

    如果此选择器不适合您的需要,请创建其他状态。在 Android res/drawable 文件夹中的 Android 的 btn_default.xml 中查找参考。

    更多参考see this

    【讨论】:

    • 谢谢,但是我完全按照你说的实现了,但是没有用。我之前读过你提到的page,但我在其他地方看到了无数关于“一体式”选择器的例子。无论如何,我将 Drawable 拆分为 3 个状态并将它们绑定到一个选择器,就像您所做的那样,它对行为没有影响。
    • 请再次检查,因为我运行此代码没有任何问题(按钮在单击时更改状态)。在 Android Emulator API 23 上测试。
    • 其他地方肯定有问题。我重建了应用程序并再次运行它 - 没有变化。如果我注释掉b.setBackground(buttonStates);,那么我会得到“默认”按钮。如果我把它留在里面,我会得到自定义的overlay_selector。除了b.setOnClickListener(),我对Button 所做的其他事情是b.setTag()b.setTransformationMethod(null)。这些都没有任何影响。我没有想法。
    • 所以你不是在扩展 xml 中的按钮?然后您可以尝试使用 [ContextThemeWrapper](developer.android.com/reference/android/view/…, int)) 并以这种方式将您的应用程序主题设置为按钮。
    • 啊,不!一定是这样的。我正在以编程方式创建和插入Button。顺便说一句,final Button b = new Button(context, null, R.drawable.overlay_button_selector); 是另一个不起作用的东西。我不熟悉ContextThemeWrapper,所以我会在几个小时后回来查看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多