另一种方法实现 Toolbar 上 menu 字体颜色的动态改变

上一个项目周期中,产品经理有了这样一个需求。

image

如上图所示,把 Toolbar 上面的菜单换成文字,而且文字颜色要根据输入内容的不同动态变化。

说实话,我并没有见过 Google 自家应用有做过这个效果的,所以特意去看了 Google 日历中创建提醒的效果。
image

效果如上图,然后通过这个效果来试图说服产品经理不要去改变颜色。。。结果很忧伤,说服不了,看来只能照做了。。。

只显示文字很简单,直接定义 title 就可以。
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="@string/action_settings"
        app:showAsAction="always" />
修改 menu 文字的固定颜色也很简单,直接在 style 里面就可以。
    <!-- 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>
        <item name="actionMenuTextColor">@color/colorAccent</item>
    </style>

但是问题来了,如果所有的 activity 都是用这个 theme 的话,那么所有 menu 上的字体颜色都会更改,如果要单独设置。

  1. 对需要修改颜色的 activity 设置单独的 theme;
  2. 对需要修改颜色的 activity 的 Toolbar 设置单独的 theme。

上面的这些只能修改固定的菜单颜色,并不能动态的改变菜单的颜色。那我们应该怎么办呢?
最简单的做法是不使用系统提供的 menu, 直接定义 TextView ,这样改变颜色就很简单了。但是这样就缺少了菜单点击时的涟漪效果。正好我当时在忙于做其它事情,我们 Android 另一个小伙伴想了另外一个办法。


    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {

        MenuItem itemSubmit = menu.findItem(R.id.submit);

        if (TextUtils.isEmpty(etMobile.getText())) {
            itemSubmit.setEnabled(false);
            itemSubmit.setTitle(Html.fromHtml("<font color='#666666'>完成</font>"));
        } else {
            itemSubmit.setEnabled(true);
            itemSubmit.setTitle(Html.fromHtml("<font color='#5CC31F'>完成</font>"));
        }

        return super.onPrepareOptionsMenu(menu);
    }

然后在需要改变颜色的地方调用 invalidateOptionsMenu();

看上去这个效果还不错,可惜的是我们测试小伙伴发现在 5.0 以下的手机上并没有效果,我们用的开发机都是 5.0 以上的,所以没有发现这个问题。那TM这就尴尬了,没办法为了适配,只能重新改了。后来找了很多办法,都没法动态的改变颜色。最后实在是没办法了,不就需要涟漪效果么?我自己给 TextView 加就可以了,说干就干。

  • 在 Toolbar 上添加 TextView:

     <android.support.v7.widget.Toolbar
          android:id="@+id/toolbar"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:background="@android:color/white"
          android:minHeight="?attr/actionBarSize"
          app:contentInsetStartWithNavigation="0dp"
          app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
          app:theme="@style/ThemeOverlay.AppCompat.ActionBar">
    
          <TextView
              android:id="@+id/tv_menu"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_gravity="right"
              android:layout_marginRight="@dimen/activity_horizontal_margin"
              android:background="?viewItemForegroundBorderless"
              android:gravity="center"
              android:text="完成"
              android:textColor="@drawable/text_color_selector_menu"
              android:textSize="16sp" />
    
      </android.support.v7.widget.Toolbar>
    
  • 设置 TextView 的 android:textColor (text_color_selector_menu.xml);
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@color/font_main_green" android:state_pressed="true" />
        <item android:color="@color/font_main_green" android:state_enabled="true" />
        <item android:color="@color/font_second_color" android:state_enabled="false" />
        <item android:color="@color/font_main_green" />
        </selector>
  • 给 TextView 设置点击涟漪效果;
  1. 在 attrs.xml 中添加:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
     <declare-styleable name="MaterialRipple">
         <attr name="viewItemBackground" format="reference" />
         <attr name="viewItemForeground" format="reference" />
         <attr name="viewItemForegroundBorderless" format="reference" />
     </declare-styleable>
    </resources>
    
  2. style 文件中添加;
    <style name="AppTheme.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <item name="viewItemBackground">?attr/selectableItemBackground</item>
    <item name="viewItemForeground">?attr/selectableItemBackground</item>
    <item name="viewItemForegroundBorderless">?attr/selectableItemBackgroundBorderless</item>
    </style>
    
  3. TextView 直接使用 android:background=”?viewItemForegroundBorderless” 就OK了。
  4. 然后在需要改变颜色的地方调用 tvMenu.setEnabled(!TextUtils.isEmpty(etMobile.getText()));;
明天去深圳干一件大事,嘿嘿嘿。。。
Smile Wei wechat
请扫码关注我的微信公众号