从源码角度简要分析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 
<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   

 
 // 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等当然不会有咯...
 


 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值