源码已上传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。
Theme.DeviceDefault的父类是Theme.Holo,这里体现了对以前版本的继承关系,Theme.DeviceDefaul中的大部分属性值,都是在Theme.Holo属性值的基础上进行再定义。Theme.DeviceDefault主题定义了对于所有组件的默认定义方式,其中包括Actionbar的属性集。如下所示:
- @android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar
- @android:style/Widget.DeviceDefault.ActionButton
- @android:style/Widget.DeviceDefault.ActionButton.Overflow
- @style/Widget.DeviceDefault.ActionBar.TabView
- @style/Widget.DeviceDefault.ActionBar.TabBar
- @style/Widget.DeviceDefault.ActionBar.TabText
- @style/Widget.DeviceDefault.ActionMode
- @style/Widget.DeviceDefault.ActionButton.CloseMode
- @android:style/Widget.DeviceDefault.ActionBar
- @android:style/Widget.DeviceDefault.PopupWindow.ActionMode
…… ……
//定义自己的APP主题 继承自Theme.DeviceDefault
//主界面应用图标
//在Activity中显示的logo取代了应用icon,logo存在缩放,可使用适当像素图片
//表示在Launcher界面显示的应用名
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();
}