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

标签 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

我不想覆盖默认值,如果我不必指定不需要的任何内容。提前致谢!

最佳答案

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

激活默认材质按钮:

旁注:总的来说,我认为使用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"/>


对于按钮,您还可以使用默认的禁用alpha属性,例如定义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并使用style对其进行应用。这些定义需要与parent对应的View

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

<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>


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

同样,您可以按每个按钮或整体在AppTheme中应用此样式。如果仍然需要支持棒棒糖之前的设备,则可能还需要一个自定义主题来设置colorButtonNormal

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

玩我的示例应用程序后,我发现阻止默认规定的文字颜色的唯一其他解释是在您的android:textColorPrimary上定义了AppTheme

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


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

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

<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应用于所有按钮,或将每个按钮用作style,如上所示。

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

在Android Studio中预览

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

关于android - 为什么setEnabled(false)不会触发主题Theme.AppCompat.Light的ColorStateList?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53071828/

相关文章:

java - 如何在 ViewModel android 中使用 mBagOfTags?

布局中的 Android 菜单选项不显示图标

android - 扩展 ActionBarActivity 时应用程序崩溃

android - 一旦顶部的回收 View 变大,如何制作固定在布局滚动底部的按钮

android - 更新Android SDK工具后无法运行应用程序

java - 安卓报警服务没有响应

java - Android 中循环随机图像

android - 我的 ActionBarActivity 布局中的奇怪行为

java - 在 Android 中的 Fragment 中使用 WebView 时,页面显示未格式化的文本

Android - ActionBar 未使用 onConfigurationChanged ( AppCompat ) 调整大小