为什么setEnabled(false)不会触发主题Theme.AppCompat.Light的ColorStateList? [英] Why doesn't setEnabled(false) trigger a ColorStateList for theme Theme.AppCompat.Light?

查看:82
本文介绍了为什么setEnabled(false)不会触发主题Theme.AppCompat.Light的ColorStateList?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

      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>< ;!-基本应用程序主题.->< style name ="AppTheme" parent ="Theme.AppCompat.Light.DarkActionBar"><!-在这里自定义主题.->< item name ="colorPrimary"> @ color/colorPrimary</item>< item name ="colorPrimaryDark"> @ color/colorPrimaryDark</item>< item name ="colorAccent"> @ color/colorAccent</item></style><!-只有这样我才能正常工作->< 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

 <应用程序android:theme ="@ style/AppTheme"(并且< activity>下没有任何内容) 

我的 MainActivity 扩展了 Activity

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

那么这是怎么回事?为什么默认设置不适用于禁用的按钮"?

  • (并且如果我确实从 Material 主题继承(如上所述),为什么Button文本的颜色没有改变?基本上,为什么Button看起来不像他们在主题编辑器中进行操作?)

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

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

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

     <!-禁用状态->< item android:state_enabled ="false" android:color =#616161"/><!-启用状态->< item android:state_enabled ="true" android:color ="@ color/colorPrimaryLighter"/><!-默认值->< item android:color =#ffffff"/> 

我的 supportLibraryVersion = '27 .1.1'

我已经看过

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

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

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

定义具有不同状态的颜色

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

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

 <!-禁用状态->< item android:state_enabled ="false" android:color =#616161"/><!-默认=启用状态->< item android:color ="@ color/colorPrimaryLighter"/> 

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

 <选择器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 .这些定义需要与 View 相对应的 parent .

使用材料按钮和最新的支持库,以前使用 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> 

这将导致如下所示的禁用按钮:

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

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

与我的示例应用程序一起玩,我发现无法防止默认的指定文字颜色的其他其他解释是在您的 AppTheme 上定义 android:textColorPrimary

 <项目名称="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 这样的选择器:

 <选择器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 即可,如上所示.

我已将我的演示项目上传到Github,其中包含更多屏幕截图/设置样式和主题的组合因为我觉得这个答案太长了,最好还是随便玩一下,以了解样式是如何工作的.

在Android Studio中预览

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

I am trying to use setEnabled(false) on a Button to show grey disabled state...

  • I can only get the desired result if I force a theme on the button with

    android:theme="@style/Button"
    

    and then change the parent on that Button style to something other than the Theme.AppCompat.Light.DarkActionBar, such as from Material:

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

    (even then, only the button background changes, the text color doesn't.)

  • I can't see the Button as grey when set disabled if I leave the Button to take the defaults. (My understanding is that when using Theme.AppCompat., Button becomes AppCompat.Widget.Button and inherits a ColorStateList.)

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

In AndroidManifest.xml

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

    ( and nothing under <activity> )

My MainActivity extends Activity

  • but I have also tried extends AppCompatActivity and had the same problem.

So what is going on here? Why doesn't the default work for a "disabled button"?

  • (And if I do inherit from Material theme (as above), why does the Button text color not change? Basically, why don't the Buttons look like they do in the theme editor?)

Also

  • when I specify a custom ColorStateList via res\color, why can't I override just some of the states? I tried to have only

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

    But it didn't work. I was only able to get a greyed disable Button using this method if I specified more <item>s, even though I don't care to match other states. It only works If I add something like:

    <!-- 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"/>
    

My supportLibraryVersion = '27.1.1'

I have already seen

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

and Nesting Android Themes

I don't want to override the defaults if I don't have to and specify anything I don't have to. Thanks in advance!

解决方案

Let me go into more detail to hopefully help clear up some of your questions:

Activating default material buttons:

Side note: Overall I think it leads to a more consistent look and behaviour when using the AppCompat Theme to also use AppCompatActivity etc.

But as you noticed just by using the AppCompat Theme, a Button (Internally mapped to android.support.v7.widget.AppCompatButton) doesn't automatically apply the compatibility material style.

I'm not sure if this is a bug, but I suspect it's to keep the look backwards compatible. You can easily activate it by applying the correct style directly on the view:

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

Here is a screenshot to show the different look of enabled and disabled buttons. The styled buttons are the first two. The active one has the pink accent color as background. The old Android button are the bottom two. As you can see disable only changes the text color and slightly the outline.

If you want this applied to any button you use in your app, you can add the following line to your AppTheme:

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

This will use your default colorAccent as button highlight color and a grey tone as a flat disabled button. You mentioned only defining the android:theme for your App in your Manifest. For this solution to work you might need to set the theme to each Activity.

Defining a color with different states

The idea of the ColorStateList is to define a color that changes depending on the state of a View. It needs the default case as a fallback in case the conditions of the specific definitions don't match.

Your example can be simplified to the following:

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

For buttons you can also make use of the default disabled alpha attribute e.g. define 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>

Custom color styling

If you are happy with the defaults, then you can ignore the following part...

If you want to style a button (and same for other components) and give it custom colors you need to make the difference between applying styles and themes. Both are defined in the styles.xml so this can be confusing. I can recommend giving the definitions names that represent how they are used.

When you want to overwrite for example the accent color, you create a custom ButtonTheme and apply it with android:theme as shown in your question.

When you want to adjust the look of a component (e.g. with the material buttons to get a different disabled color), you create a custom ButtonStyle and apply it with style. These definitions need a parent that corresponds to the View.

With material buttons and latest support libraries the previous approach to set the disabled color with colorButtonNormal seems to not work anymore. Instead you can use the color defined in the previous step by creating a custom style and set it as 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>

This will lead to a disabled button like this:

Again you can apply this style as above per button or overall in your AppTheme. If you still need to support pre-lollipop devices you probably will also need a custom theme to set the colorButtonNormal.

Update: Default Material + stated text color:

Played with my example app and the only other explanation I found to what prevents the default stated text color is defining android:textColorPrimary on your AppTheme!

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

If you have this all buttons without a custom text color will use this text for both states! See Screenshot.

If you just want to fix the button text to change color, you can define your button style like this:

<style name="AppTheme.TextStatedButtonStyle" parent="@style/Widget.AppCompat.Button.Colored">
    <item name="android:textColor">@color/button_text_stated</item>
</style>

With button_text_stated a selector like this:

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

And simply apply this buttonStyle for all buttons or as style per button as shown above.

I've uploaded my demo project with more screenshots / combinations of setting styles and themes to Github since I felt this answer was getting too long and it's better to just play with it to understand how styles work.

Preview in Android studio

As mentioned in the comments I can confirm that the Preview in Android studio is sometimes showing elements wrong, especially when applying a custom theme to an element! Better to test in the emulator or on a real device.

这篇关于为什么setEnabled(false)不会触发主题Theme.AppCompat.Light的ColorStateList?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆