您的位置:首页 > 其它

从源码角度简要分析ActionBar框架

2015-05-23 10:40 537 查看

转载请注明出处:
http://blog.csdn.net/qinjuning

Android3.0 以后 Menu相关做了较大改变。ActionBar作为新的Menu形式粉墨登场了。

3.0之后常见的Menu或ActionBar有这四种:





图1:普通的ContextMenu
图2: ActionBar





图3: ActionMode(Contxt-ActionBar) 图4 屏幕下方的ActionBar-代码里称之为splitActionBar

ContextMenu, 为某个View registerContextMenu后,显示效果如图一。

调用流程为: 长按 ->showContextMenu -> DecorView:: showContextMenuForChild() , 此时会创建一个ContextMenuBuilder ,对应show一个MenuDialogHelper类,该类主要已listPopup的展示所有menuItem
—> ContextMenuBuilder::show() ,调用createContextMenu创建ContextMenu项 —>View::createContextMenu() -> Activity::onCreateContextMenu()创建MenuItem()。

至此,ContextMenu的创建流程走完了。

注意: 有些控件例如ListView等,会特殊处理长按事件的默认操作,即采用ActionMode模式,而不是ContextMenu菜单。例如:AbsListView中performLongPress()中会判断是否设置了CHOICE_MODE_MULTIPLE_MODAL标记,如果设置了,即调用startActionMode
转换为ActionMode模式。

ActionBar初始化过程,

回到PhoneWindow::installDecorView中。3.0之后的默认布局就是:screen_action_bar.xml , 对应布局如下:
screen_action_bar.xml

[java] view
plaincopyprint?





<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:fitsSystemWindows="true"

android:orientation="vertical" >

<com.android.internal.widget.ActionBarContainer

android:id="@+id/action_bar_container"

style="?android:attr/actionBarStyle"

android:layout_width="match_parent"

android:layout_height="wrap_content" >

<com.android.internal.widget.ActionBarView

android:id="@+id/action_bar"

style="?android:attr/actionBarStyle"

android:layout_width="match_parent"

android:layout_height="wrap_content" />

<com.android.internal.widget.ActionBarContextView

android:id="@+id/action_context_bar"

style="?android:attr/actionModeStyle"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:visibility="gone" />

</com.android.internal.widget.ActionBarContainer>

<FrameLayout

android:id="@android:id/content"

android:layout_width="match_parent"

android:layout_height="0dip"

android:layout_weight="1"

android:foreground="?android:attr/windowContentOverlay"

android:foregroundGravity="fill_horizontal|top" />

<com.android.internal.widget.ActionBarContainer

android:id="@+id/split_action_bar"

style="?android:attr/actionBarSplitStyle"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center"

android:visibility="gone" />

</LinearLayout>

会初始化以下几个自定义View:

ActionBarContainer : FrameLayout,管理下面的ActionBarView 和 ActionBarContextView ,只会visible一个View。

ActionBarView (对应图2):: com.android.internal.widget.ActionBarView
用于显示各种Menu的ViewGroup

ActionBarContextView (对应图3) :默认Gone, 这个自定义ViewGroup用来显示ActionMode下的Menu

ActionBarContainer -- splitActionBar (对应图4):
默认Gone, 当Menu过多时,可以将菜单放到该视图上。
判断是否需要显示splitActionBar是在PhoneWindow::installDecor创建的。即
android:uiOptions="splitActionBarWhenNarrow",默认是true.如果设置了,Menu将显示在该View上。

显示ActionBar的过程如下:

installDecor@PhoneWindowjaa

[java] view
plaincopyprint?





// Post the panel invalidate for later; avoid application onCreateOptionsMenu

// being called in the middle of onCreate or similar.

mDecor.post(new Runnable() {

public void run() {

// Invalidate if the panel menu hasn't been created before this.

PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);

if (!isDestroyed() && (st == null || st.menu == null)) {

invalidatePanelMenu(FEATURE_ACTION_BAR);

}

}

});

此时会获取Activity对应的 PanelFeatureState 对象。

—> PhoneWindow::preparePanel(PanelFeatureState st, KeyEvent event)
—> PhoneWindow::initializePanelMenu(st) ,会创建一个MenuBuilder对象,以后所有Menu就归他管理了,为ActionBar setMenu。
—> cb.onCreatePanelMenu(st.featureId, st.menu), 默认就是Activity的方法了。
—> Activity::onCreatePanelMenu , 创建MenuItem
—> cb.onPreparePanel(),默认就是Activity的方法了, onPrepare。

支持ActionBar对应的MenuBuilder也全部初始化OK了。

ActionBarView 管理了以下几种布局:
HomeLayout -- 显示左侧的应用程序图标,回退箭头等;

TitleLayout -- 如果存在titile,subtile则显示
不同模式下的视图:
STANDARD : ActionMenuView
MODE_LIST: adapter mSpinner, 通过代码setDropdownAdapter设置适配器
MODE_TAB : tab ScrollingTabContainerView ,管理所有TabView, ScrollingTabContainerView.TabView, 其选中背景图由selected熟悉控制.

MODE_LIST 和 MODE_TAB对应的视图只能add 其中1个。

ExpandView -- 如果某个Menu设置了 android:actionViewClass,即能expand collapse。
如果展开时,其他视图置为GONE状态,只显示HomeLayout和该ExpandView。

ActionBarView 得自动实现measure和layout操作。

ActionBarContainer -- splitActionBar
单纯管理一个 ActionMenuView。

ActionBarContextView 即处于ActionMode模式下的视图管理

自动在最左侧添加一个√的CloseButton。
可以设置TitleLayout或者自定义的CustomView
管理一个 ActionMenuView。 initForMode方法时会初始化1个ActionMenuPresenter,提供该视图。

ActionMenuView 核心主角登场,掌声鼓励。

功能:管理MenuItem的视图容器。每个Menu作为一个cell,如果在屏幕上显示不全,则会自动创建一个更多的View。

measure 或layout时,计算较为复杂。每个cell有个最小宽度单位。

ActionMenuItemView: 对应于每个MenuItem的View。由ActionMenuView管理。

BaseMenuPresenter: 根据MenuBuiler为每个MenuItem创建ActionMenuItemView
或自定义的 actionClass----由 android:actionViewClass 或者android:actionProvider提供。

方法解析:
initForMenu : Menu设置
getMenuView: 获得创建的ActionMenuView
视图容器
updateMenuView : 更新ActionMenuView
的子View
getItemView : 为每个MenuItem创建View对象
addItemView : 将创建的View对象添加至ActionMenuView 视图容器中。
bindItemView: 绑定数据

ActionMenuPresenter 继承于BaseMenuPresenter ,其构造方法提供了两个视图,分别传递Action ViewGroup和 Action View对象,用于其父类初始话布局对象。并且它重写了getItemView方法,
如果MenuItem提供了actionView则用它,否则用系统定义好的。另外,如果某个MenuItem 为expand或者collapse状态,则MenuPresenter相关事件会回调,更改MenuItem VISBILE状态。

点击回调事件流程:

ActionMenuItemView::onClick()
—>ActionMenuView::invokeItem
—> MenuBuilder::performItemAction
—> MenuItemImpl:: invoke()
—> MenuBuilder:: dispatchMenuItemSelected
,此时的Callback为PhoneWindow对象。

如果为ActionMode模式,

startActionMode() ,转换为ActionMode模式。流程如下:

PhoneWindow:: startActionMode()

—>
Activity :: onWindowStartingActionMode

—> ActionBarImpl:: startActionMode 转换为ActionMode模式,初始化1个ActionModeImpl对象(内部构造1个新的MenuBuilder,用来管理该模式下的Menu),同时ActionContextView
Visbile, ActionBarView隐藏。

—> 继续调用 ActionBarImpl
:: dispatchOnCreate() , 回调Activity的onCreateActionMode 生成MenuItem

ActionMode的回调如下: ActionModeImpl:: onMenuItemSelected 继续回调给 PhoneWindow相关方法

ActionBarView::expandItemActionView 打开某个MenuItem对应的actionView, 会设置mExpandedActionView
请求重绘视图
ActionBarView::collapseItemActionView 折叠某个MenuItem对应的actionView

ActionProvider

提供actionViewClass 以及对应的操作。对应的View由onCreateActionView()返回。

吐槽下:发现csdn的博客编辑器还没有有道云笔记让人舒坦,悲了个催。

备注:Android 2.X使用ActionBar得使用ActionBarSherlock 和 v7
appcompat library

使用注意: ①、两者皆不支持Float Button,即自动显示更多的按钮.
②、ActionMode等当然不会有咯..
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: