为什么setEnabled(false)不会触发主题Theme.AppCompat.Light的ColorStateList?

时间:2018-10-30 19:45:24

标签: android android-layout android-appcompat

我正在尝试在setEnabled(false)上使用Button来显示灰色的禁用状态...

  • 仅当我使用按钮强制主题时,我才能获得所需的结果

    android:theme="@style/Button"
    

    ,然后将该Button样式的父级更改为Theme.AppCompat.Light.DarkActionBar之外的其他名称,例如从Material:

    <style name="Button" parent="android:Theme.Material.Light.NoActionBar">
    

    (即使那样,仅按钮背景会更改,文本颜色不会更改。)

  • 如果设置为禁用,我不能将其视为灰色,如果我将按钮保留为默认值。 (我的理解是,使用Theme.AppCompat.时,Button变成AppCompat.Widget.Button并继承了ColorStateList。)

在我的res\values\styles.xml

    <resources>
        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
        </style>        
        <!-- only way I could get this to work -->
        <style name="Button" parent="android:Theme.Material.Light.NoActionBar">
            <!--<item name="colorAccent">@color/butt</item>-->
            <!--<item name="colorButtonNormal">@color/butt</item>-->
        </style>        
        <style name="AppTheme.NoActionBar">
            <item name="windowActionBar">false</item>
            <item name="windowNoTitle">true</item>
        </style>        
        <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
        <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
    </resources>

AndroidManifest.xml

    <application
    android:theme="@style/AppTheme"

    ( and nothing under <activity> )

我的MainActivity扩展了Activity

  • 但是我也尝试过扩展AppCompatActivity并遇到相同的问题。

那么这是怎么回事?为什么默认设置对“禁用的按钮”无效?

  • (并且如果我确实继承自Material主题(如上),为什么Button文本的颜色不会改变?基本上,为什么Button看上去不像它们在主题编辑器?)

  • 当我通过ColorStateList指定自定义res\color时,为什么不能仅覆盖某些状态?我试着只有

    <item android:state_enabled="false" android:color="#616161" />
    

    但是没有用。即使我不希望匹配其他状态,也只能通过指定更多<item>来使用此方法获得灰色的禁用按钮。仅当我添加类似内容时,它才有效:

    <!-- disabled state -->
    <item android:state_enabled="false" android:color="#616161" />    
    <!-- enabled state -->
    <item android:state_enabled="true" android:color="@color/colorPrimaryLighter" />    
    <!-- default -->
    <item android:color="#ffffff"/>
    

我的supportLibraryVersion = '27.1.1'

我已经看过

How to setup disabled color of button with AppCompat?

Widget.AppCompat.Button colorButtonNormal shows gray

State list drawable and disabled state

Android - default button style

Android: change color of disabled text using Theme/Style?

When should one use Theme.AppCompat vs ThemeOverlay.AppCompat?

Use android:theme and ThemeOverlay to theme specific Views and their descendents Pro-tip by +Ian Lake

Nesting Android Themes

如果不需要,我不想覆盖默认值并指定不需要的任何内容。预先感谢!

1 个答案:

答案 0 :(得分:0)

让我详细介绍一下,希望可以帮助您解决一些问题:

激活默认材质按钮:

侧面说明:总的来说,我认为使用AppCompat主题同时使用AppCompatActivity等时,外观和行为也会更加一致。

但是,正如您注意到的那样,仅通过使用AppCompat主题,Button(内部映射到android.support.v7.widget.AppCompatButton)不会自动应用兼容性材料样式。

我不确定这是否是错误,但我怀疑这是为了保持向后兼容。您可以通过直接在视图上应用正确的样式来轻松激活它:

<Button
   style="@style/Widget.AppCompat.Button.Colored"
   ... />

以下是屏幕截图,显示了已启用和已禁用按钮的不同外观。 样式按钮是前两个。活动对象具有粉红色的重音颜色作为背景。 旧的Android按钮是底部的两个。如您所见,禁用仅会更改文本颜色和略微的轮廓。

Buttons in different styles

如果要将其应用于您在应用中使用的任何按钮,则可以将以下行添加到AppTheme

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
   <item name="buttonStyle">@style/Widget.AppCompat.Button.Colored</item>
   ...

这将使用默认的colorAccent作为按钮突出显示颜色,并使用灰色调作为禁用的平面按钮。您提到仅在清单中为android:theme定义App。为了使该解决方案有效,您可能需要将主题设置为每个Activity

定义具有不同状态的颜色

ColorStateList的想法是定义根据View的状态而变化的颜色。如果特定定义的条件不匹配,则需要使用默认情况作为后备。

您的示例可以简化为以下内容:

<!-- disabled state -->
<item android:state_enabled="false" android:color="#616161" />
<!-- default = enabled state -->
<item android:color="@color/colorPrimaryLighter"/>

对于按钮,您还可以使用默认的禁用的字母属性,例如定义button_accent_stated =

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="false"
          android:alpha="?android:attr/disabledAlpha"
          android:color="@color/colorAccent"/>
    <item android:color="@color/colorAccent" />
</selector>

自定义颜色样式

如果您对默认设置感到满意,则可以忽略以下部分...

如果您想为按钮设置样式(其他组件也是如此)并为其指定自定义颜色,则需要应用样式和主题之间的区别。两者都在styles.xml中定义,因此可能会造成混淆。我可以建议给定义起一个代表它们如何使用的名称。

例如,当您要覆盖点缀颜色时,请创建一个自定义ButtonTheme ,并按照问题中的说明将其与android:theme一起应用。

当您要调整组件的外观时(例如,使用材料按钮来获得不同的禁用颜色),可以创建一个自定义ButtonStyle 并与{{1 }}。这些定义需要一个style对应的parent

使用材料按钮和最新的支持库,以前用View设置禁用颜色的方法似乎不再起作用。相反,您可以通过创建自定义样式并将其设置为colorButtonNormal来使用上一步中定义的颜色。

backgroundTint

这将导致如下所示的禁用按钮: Disabled with alpha accent color

同样,您可以在每个按钮上或在<style name="AppTheme.ButtonStyle" parent="@style/Widget.AppCompat.Button.Colored"> <item name="colorAccent">@color/colorAccent</item> <item name="android:backgroundTint">@color/button_accent_stated</item> </style> 中整体应用此样式。如果您仍然需要支持棒棒糖之前的设备,则可能还需要一个自定义主题来设置AppTheme

更新:默认材料+文字颜色:

在我的示例应用程序中玩耍,我发现唯一可以防止默认规定的文字颜色的解释是在colorButtonNormal上定义android:textColorPrimary

AppTheme

如果所有按钮都没有自定义文字颜色,则这两种状态都将使用此文字!参见Screenshot

如果您只想修复按钮文本以更改颜色,则可以这样定义按钮样式:

<item name="android:textColorPrimary">@color/colorPrimaryTextOnLight</item>

使用<style name="AppTheme.TextStatedButtonStyle" parent="@style/Widget.AppCompat.Button.Colored"> <item name="android:textColor">@color/button_text_stated</item> </style> 这样的选择器:

button_text_stated

只需将<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?android:disabledAlpha" android:color="@color/colorPrimaryTextOnLight" /> <item android:color="@color/colorPrimaryTextOnDark" /> </selector> 应用于所有按钮,或将每个按钮分别用作buttonStyle,如上所示。

我已经将demo project的更多屏幕截图/设置样式和主题组合上传到了Github,因为我觉得这个答案太长了,最好还是自己玩一遍,以了解样式的工作原理。

在Android Studio中预览

如评论中所述,我可以确认Android Studio中的预览有时会显示错误的元素,尤其是在将自定义主题应用于元素时!最好在模拟器或真实设备上进行测试。