源码已上传http://download.csdn.net/detail/klpchan/6830221,格式不太整洁,仅供参考。
上一篇介绍了ActionBar的选项内容和菜单项,项目中会遇到需要自定义风格的标题栏,CustomView不建议用来定义控件风格,因为没有用到ActionBar的默认组件,如果UIDesigner完全自主设计了一套看起来怎么都不像谷歌建议的AB布局,可以考虑CustomView,大部分情况只是要修改一下例如Title的字体或者标题栏背景。
按照项目中的需求和网上论坛常见的内容,自定义标题栏风格包括以下几项:
Q1.1 修改标题栏字体大小、颜色、样式
Q1.2 自定义ActionBar背景颜色及AB高度
Q1.3 修改ActionBar上菜单项字体样式
Q2 在ActonBar上显示与Launch界面不同的Title的icon
Q3 在含有菜单键的手机上强制显示溢出菜单
Q4 防止应用启动时ActionBar上默认图标和标题的闪烁
本文将以上问题打包解答,问题虽多,但是解决思路类路类似。
Q1的几个问题属于一类,看一张图先。
这张是Android系统主题变化流程简图,API 10 及以前的版本,用的是Theme主题,主题属性集定义在Theme.xml中,主题属性值在Style.xml中,API11~13的版本时,默认主题使用的是Theme.Holo,属性集和属性值得定义文件同上,从API14也就是ICS之后,Theme.DeviceDefault作为新的主题,使用了新的文件,如上图所示。本文中以API14为最低版本,默认使用的主题是android/framework/base/core/res/res/values/themes_device_defaults.xml中的Theme.DeviceDefault。
<style name="Theme.DeviceDefault" parent="Theme.Holo" >
Theme.DeviceDefault的父类是Theme.Holo,这里体现了对以前版本的继承关系,Theme.DeviceDefaul中的大部分属性值,都是在Theme.Holo属性值的基础上进行再定义。Theme.DeviceDefault主题定义了对于所有组件的默认定义方式,其中包括Actionbar的属性集。如下所示:
<!-- Action bar styles --> <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item> <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item> <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item> <item name="actionBarTabStyle">@style/Widget.DeviceDefault.ActionBar.TabView</item> <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.ActionBar.TabBar</item> <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.ActionBar.TabText</item> <item name="actionModeStyle">@style/Widget.DeviceDefault.ActionMode</item> <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item> <item name="actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar</item> <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
<style name="Widget.Holo.ActionBar" parent="Widget.ActionBar"> <item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Title</item> <item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item> <item name="android:background">@android:drawable/ab_transparent_dark_holo</item> <item name="android:backgroundStacked">@android:drawable/ab_stacked_transparent_dark_holo</item> <item name="android:backgroundSplit">@android:drawable/ab_bottom_transparent_dark_holo</item> <item name="android:divider">?android:attr/dividerVertical</item> <item name="android:progressBarStyle">@android:style/Widget.Holo.ProgressBar.Horizontal</item> <item name="android:indeterminateProgressStyle">@android:style/Widget.Holo.ProgressBar</item> <item name="android:progressBarPadding">32dip</item> <item name="android:itemPadding">8dip</item> </style>
<style name="TextAppearance.Holo.Widget.ActionBar.Title" parent="TextAppearance.Holo.Medium"> <item name="android:textSize">@android:dimen/action_bar_title_text_size</item> </style><style name="TextAppearance.Holo.Medium" parent="TextAppearance.Medium"> </style> …… <style name="TextAppearance.Medium"> <item name="android:textSize">18sp</item> </style> …… <style name="TextAppearance"> <item name="android:textColor">?textColorPrimary</item> <item name="android:textColorHighlight">?textColorHighlight</item> <item name="android:textColorHint">?textColorHint</item> <item name="android:textColorLink">?textColorLink</item> <item name="android:textSize">16sp</item> <item name="android:textStyle">normal</item> </style>
<style name="MyTheme" parent="@android:style/Theme.DeviceDefault"></style> //定义自己的APP主题 继承自Theme.DeviceDefault <style name="MyTheme.WithActionBar" parent="@style/MyTheme"> <item name="android:actionBarStyle">@style/MyActionBarStyle</item> //在APP主题中使用自定义的actionBarStyle </style> <style name="MyActionBarStyle" parent="android:style/Widget.DeviceDefault.ActionBar"> //自定义的actionBarStyle,需继承自Widget.DeviceDefault.ActionBar <item name="android:titleTextStyle">@style/MyTitleTextStyle</item> //在MyActionBarStyle中使用自定义的titleTextStyle属性 </style> <style name="MyTitleTextStyle" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title"> //自定义titleTextStyle属性,父类同源码 <item name="android:textSize">30sp</item> <item name="android:textColor">#FFFF00</item> //自定义title大小及颜色 </style>
</style> <style name="Widget.DeviceDefault.ActionButton" parent="Widget.Holo.ActionButton" > </style> <style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Holo.ActionButton.Overflow" > </style> <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Holo.ActionButton.TextButton" > </style> <style name="Widget.DeviceDefault.ActionMode" parent="Widget.Holo.ActionMode" > </style> <style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Holo.ActionButton.CloseMode" > </style> <style name="Widget.DeviceDefault.ActionBar" parent="Widget.Holo.ActionBar" >
styles.xml内容如下,在AndroidManifest中注册android:theme="@style/MyTheme.WithActionBar"。
<style name="MyTheme" parent="@android:style/Theme.DeviceDefault"></style> <style name="MyTheme.WithActionBar" parent="@style/MyTheme"> <item name="android:actionMenuTextAppearance">@style/MyABmenuTextAppearance</item> // 使用自定义的菜单文本风格 <item name="android:actionMenuTextColor">#FF4500</item> //定义ActionItem字体颜色 <item name="android:actionBarStyle">@style/MyActionBarStyle</item> // 使用自定义的actionBarStyle </style> <style name="MyActionBarStyle" parent="android:style/Widget.DeviceDefault.ActionBar"> <item name="android:background">#90EE90</item> //定义ActionBar背景颜色 <item name="android:height">60dip</item> // 定义ActionBar高度 <item name="android:titleTextStyle">@style/MyTitleTextStyle</item> <item name="android:subtitleTextStyle">@style/MySubTitleTextStyle</item> </style> <style name="MyTitleTextStyle" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title"> <item name="android:textSize">30sp</item> <item name="android:textColor">#FFFF00</item> //修改标题字体大小及颜色 </style> <style name="MySubTitleTextStyle" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle"> <item name="android:textColor">#FFC0CB</item> //修改子标题字体颜色 </style> <style name="MyABmenuTextAppearance" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Menu"> <item name="android:textSize">13sp</item> <item name="android:textStyle">bold</item> //修改AB菜单项字体风格 </style>
<application …… android:icon="@drawable/appIcon"> //主界面应用图标 <activity android:label="@string/activityname" //在Activity中显示的标题 android:logo="@drawable/activitiyIcon"> //在Activity中显示的logo取代了应用icon,logo存在缩放,可使用适当像素图片 <intent-filter android:label="@string/appname"> //表示在Launcher界面显示的应用名 <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
try { ViewConfiguration config = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); if(menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(config, false); } } catch (Exception ex) { // Ignore }
ActionMenuView menuView; final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); if (!mSplitActionBar) { mActionMenuPresenter.setExpandedActionViewsExclusive( getResources().getBoolean( com.android.internal.R.bool.action_bar_expanded_action_views_exclusive)); configPresenters(builder); menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); final ViewGroup oldParent = (ViewGroup) menuView.getParent(); if (oldParent != null && oldParent != this) { oldParent.removeView(menuView); } addView(menuView, layoutParams); } else { mActionMenuPresenter.setExpandedActionViewsExclusive(false); // Allow full screen width in split mode. mActionMenuPresenter.setWidthLimit( getContext().getResources().getDisplayMetrics().widthPixels, true); // No limit to the item count; use whatever will fit. mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); // Span the whole width layoutParams.width = LayoutParams.MATCH_PARENT; configPresenters(builder); menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); if (mSplitView != null) { final ViewGroup oldParent = (ViewGroup) menuView.getParent(); if (oldParent != null && oldParent != mSplitView) { oldParent.removeView(menuView); } menuView.setVisibility(getAnimatedVisibility()); mSplitView.addView(menuView, layoutParams); } else { // We'll add this later if we missed it this time. menuView.setLayoutParams(layoutParams); } }
private void configPresenters(MenuBuilder builder) { if (builder != null) { builder.addMenuPresenter(mActionMenuPresenter); builder.addMenuPresenter(mExpandedMenuPresenter); } else { mActionMenuPresenter.initForMenu(mContext, null); mExpandedMenuPresenter.initForMenu(mContext, null); mActionMenuPresenter.updateMenuView(true); mExpandedMenuPresenter.updateMenuView(true); } }
final ActionBarPolicy abp = ActionBarPolicy.get(context); if (!mReserveOverflowSet) { mReserveOverflow = abp.showsOverflowMenuButton(); } public boolean showsOverflowMenuButton() { return !ViewConfiguration.get(mContext).hasPermanentMenuKey(); }
<style name="MyActionBarStyle" parent="android:style/Widget.DeviceDefault.ActionBar"> <item name="android:displayOptions">showCustom</item> //添加该行,表示默认显示的是CustomView。 <item name="android:background">#90EE90</item> <item name="android:height">60dip</item> <item name="android:titleTextStyle">@style/MyTitleTextStyle</item> <item name="android:subtitleTextStyle">@style/MySubTitleTextStyle</item> </style>
<style name="Widget.ActionBar"> <item name="android:background">@android:drawable/action_bar_background</item> <item name="android:displayOptions">useLogo|showHome|showTitle</item> <item name="android:divider">@android:drawable/action_bar_divider</item> <item name="android:height">?android:attr/actionBarSize</item> <item name="android:paddingStart">0dip</item> <item name="android:paddingTop">0dip</item> <item name="android:paddingEnd">0dip</item> <item name="android:paddingBottom">0dip</item> <item name="android:titleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Title</item> <item name="android:subtitleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Subtitle</item> <item name="android:progressBarStyle">@android:style/Widget.ProgressBar.Horizontal</item> <item name="android:indeterminateProgressStyle">@android:style/Widget.ProgressBar.Small</item> <item name="android:homeLayout">@android:layout/action_bar_home</item> </style>