其实做原生 Android 开发这么久,对 Android 的原生控件还是比较满意的,毕竟 Material Design 也不是吃素的,但是目前不太满意的地方可能就是 Menu
了。
原生 Menu
的默认样式其实和其他控件一样,都是十分简约的。
可以发现,默认的 Menu
当 Item 折叠的时候,下拉的 Menu
是会把 Toolbar
挡住的,虽然这并不影响我们的使用,但是却和我们既有的交互习惯相悖,而且默认的白色背景也和我们的主题颜色不搭,所以我们需要根据我们的需要定制。
但定制的时候,你会发现定制的方式比其他控件要相对繁琐,不像其他控件一样,只需要到相应的 layout 文件中修改控件的属性即可,它还需要修改其 values 文件并在 layout 中引用才行。
首先修改「styles.xml」文件,添加一个 <style>
定义其 Style 属性:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="actionOverflowMenuStyle">@style/OverflowMenu</item>
</style>
<style name="OverflowMenu" parent="Base.Widget.AppCompat.PopupMenu.Overflow">
<item name="overlapAnchor">false</item>
<item name="android:popupBackground">@color/colorPrimary</item>
</style>
</resources>
其中 overlapAnchor
是用来修改 Menu
悬浮位置的,默认为 TRUE
,当为 FALSE
的时候则不遮挡 Toolbar
。
如果使用的是 Toolbar
而不是默认的 ActionBar
,则不要忘了在 Toolbar
控件中添加 app:popupTheme
属性:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/OverflowMenu" />
为了符合 Material Design 以及开发方便需要,十分建议使用 Toolbar
而不是 ActionBar
,在定制 Menu
这个场景中,如果使用 ActionBar
则还需要使用比较繁琐的方法手动修改 Menu
中的字体颜色,而 Toolbar
只需定义好其主题即可自动修改。
android:popupBackground
则是用来修改下拉 Menu
时的背景颜色,默认是深灰色,我这里则把它设置为与 Toolbar
一样,这样会比较和谐。
Toolbar
上的 Menu
我们一般都会为其设置 ICON,因为用户对图形的感知会强于文字,所以 ICON 很重要,但是 Menu 默认情况下只会在 Toolbar 上显示 ICON,而下拉则仅显示文字,这就十分不友好了,甚至还浪费了美工的设计成果,必须要改。
但是这个居然在样式文件中是不能直接设置的,需要到 Activity 中通过反射设置其显示。
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (menu != null) {
if (menu.getClass() == MenuBuilder.class) {
try {
Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
method.setAccessible(true);
method.invoke(menu, true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return super.onMenuOpened(featureId, menu);
}
这样,就能够将 ICON 和文字同时显示出来了。
还有在最近的开发中我比较喜欢一体化布局,即 Toolbar
和下方融为一体,虽然不知道 Material Design 是否推崇这种设计方式,但我个人还是觉得挺好看的。
那么就会出现一种情况,Menu
的「More」三个点是默认的,颜色也是跟随默认的主题,那么如果我在项目中想修改它的颜色也会比较麻烦,如下:
我一开始的想法是,会有一个关于 Color
的属性让我可以直接设置,但是怎么找都找不到,无奈之下只能选择其他方式,修改这个默认的图标。
先导入一个喜欢的 ICON,我这里在『Android Studio』中提供的图标库中选择了跟原来相同的「more vert」图标,并修改为合适的颜色。
然后在「styles.xml」文件中添加一个新的 <style>
:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="actionOverflowMenuStyle">@style/OverflowMenu</item>
<item name="actionOverflowButtonStyle">@style/OverflowButtonStyle</item>
</style>
...
<style name="OverflowButtonStyle" parent="Base.Widget.AppCompat.ActionButton.Overflow">
<item name="android:src">@drawable/ic_more</item>
</style>
</resources>
这里通过指定 actionOverflowButtonStyle
的 Style 设定其图标。
同时,我还想指定 Menu
中的字体颜色,那么我可以添加属性:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="actionOverflowMenuStyle">@style/OverflowMenu</item>
<item name="actionOverflowButtonStyle">@style/OverflowButtonStyle</item>
<item name="actionMenuTextColor">@android:color/white</item>
</style>
...
</resources>
只需指定 actionMenuTextColor
的颜色即可,我在这里直接指定为白色。
其实 Menu
还有其他可定制的属性,比如背景透明之类的,但都不能直接在 layout 中修改控件属性,所以的确是比较折腾的。