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

                                                        转载请注明出处: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 
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:fitsSystemWindows="true"  
  3.     android:orientation="vertical" >  
  4.   
  5.     <com.android.internal.widget.ActionBarContainer  
  6.         android:id="@+id/action_bar_container"  
  7.         style="?android:attr/actionBarStyle"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="wrap_content" >  
  10.   
  11.         <com.android.internal.widget.ActionBarView  
  12.             android:id="@+id/action_bar"  
  13.             style="?android:attr/actionBarStyle"  
  14.             android:layout_width="match_parent"  
  15.             android:layout_height="wrap_content" />  
  16.   
  17.         <com.android.internal.widget.ActionBarContextView  
  18.             android:id="@+id/action_context_bar"  
  19.             style="?android:attr/actionModeStyle"  
  20.             android:layout_width="match_parent"  
  21.             android:layout_height="wrap_content"  
  22.             android:visibility="gone" />  
  23.     </com.android.internal.widget.ActionBarContainer>  
  24.   
  25.     <FrameLayout  
  26.         android:id="@android:id/content"  
  27.         android:layout_width="match_parent"  
  28.         android:layout_height="0dip"  
  29.         android:layout_weight="1"  
  30.         android:foreground="?android:attr/windowContentOverlay"  
  31.         android:foregroundGravity="fill_horizontal|top" />  
  32.   
  33.     <com.android.internal.widget.ActionBarContainer  
  34.         android:id="@+id/split_action_bar"  
  35.         style="?android:attr/actionBarSplitStyle"  
  36.         android:layout_width="match_parent"  
  37.         android:layout_height="wrap_content"  
  38.         android:gravity="center"  
  39.         android:visibility="gone" />  
  40.   
  41. </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   

 
  1. // Post the panel invalidate for later; avoid application onCreateOptionsMenu  
  2. // being called in the middle of onCreate or similar.  
  3. mDecor.post(new Runnable() {  
  4.    public void run() {  
  5.       // Invalidate if the panel menu hasn't been created before this.  
  6.       PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);  
  7.       if (!isDestroyed() && (st == null || st.menu == null)) {  
  8.            invalidatePanelMenu(FEATURE_ACTION_BAR);  
  9.       }  
  10.    }  
  11. });      
   
此时会获取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等当然不会有咯..
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值