Android ActionBar的源代码分析(四)

Linux中断子系统分析之(四):驱动程序申请中断 中断子系统中有一个重要的设计机制,那就是Top-half和Bottom-half,将紧急的工作放置在Top-half中来处理,而将耗时的工作放置在Bottom-half中来处理。 如果中断不分上下半部处理,那么意味着只有等上一个中断完成处理后才会打开中断,下一个中断才能得到响应。当某个中断处理处理时间较长时,很有可能就会造成其他中断丢失而无法响应,影响系统性能。 中断分成上下半部处理可以提高中断的响应能力,在上半部处理完成后便将中断打开,这样就可以响应其他中断了,等到中断退出的时候再进行下半部的处理。为了进 阅读详情

上一篇已经对ActionBar的菜单项的执行过程进行了分析,有兴趣的朋友可以看一下android中ActionBar的源代码分析(三),本章对ActionBar的OverflowMenu的运行机制进行分析。

ActionBar的OverflowMenu,就是ActionBar右边的三个小点点,点击以后就出现一个下拉菜单项,如图

OverflowMenu是为了解决ActionBar的菜单项太多,在一个屏幕上显示不出来,而把过多的菜单项放到下拉菜单中显示的问题;在配置菜单属性的时候,把android:showAsAction设为ifRoom或者never,就会利用ActionBar的OverflowMenu特性在下拉菜单显示出来了,当然如果你的机器是带有物理menu键的,还需要进行特殊处理,这个可以看一下我之前写的一篇文章android2.x使用ActionBar-强制显示OverflowButton

溢出菜单按钮的构建

既然我们知道了如何使用OverflowMenu,那这个OverflowMenu在代码层次是如何实现的呢?从上几篇文章我们知道,类ActionMenuPresenter是负责ActionBar菜单项的绘制工作的,其中初始菜单参数的方法是initForMenu(),我们先看一下这个代码是如何实现的吧。

    @Override
    public void initForMenu(Context context, MenuBuilder menu) {
        super.initForMenu(context, menu);

        final Resources res = context.getResources();
<span style="white-space:pre">	</span>//是否显示溢出菜单按钮
        final ActionBarPolicy abp = ActionBarPolicy.get(context);
        if (!mReserveOverflowSet) {
            mReserveOverflow = abp.showsOverflowMenuButton();
        }
<span style="white-space:pre">	</span>//嵌入菜单最大宽度即放置ActionBar菜单项的最大宽度
        if (!mWidthLimitSet) {
            mWidthLimit = abp.getEmbeddedMenuWidthLimit();
        }
<span style="white-space:pre">	</span>//ActionBar最多显示的按钮数目
        // Measure for initial configuration
        if (!mMaxItemsSet) {
            mMaxItems = abp.getMaxActionButtons();
        }
<span style="white-space:pre">	</span>//初始化溢出菜单按钮,并计算溢出菜单按钮宽度
        int width = mWidthLimit;
        if (mReserveOverflow) {
            if (mOverflowButton == null) {
                mOverflowButton = new OverflowMenuButton(mSystemContext);
                final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                mOverflowButton.measure(spec, spec);
            }
            width -= mOverflowButton.getMeasuredWidth();  //显示的菜单按钮宽度需要减掉溢出菜单按钮的宽度
        } else {
            mOverflowButton = null;
        }

        mActionItemWidthLimit = width;

        mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);

        // Drop a scrap view as it may no longer reflect the proper context/config.
        mScrapActionButtonView = null;
    }
这段代码首先调用父类(BaseMenuPresenter)的initForMenu()方法,父类的这个方法无非就是一些赋值操作,代码就不贴出来了,然后就根据ActionBarPolicy确定是否显示溢出菜单按钮(OverflowButton)以及ActionBar最多显示的菜单数目,最后对溢出菜单按钮进行初始化操作并计算溢出菜单按钮的宽度。可以看到,这里涉及了很多宽度的获取,包括嵌入的菜单宽度、最大按钮显示数目和溢出菜单按钮的宽度,其实就是为了确定当菜单配置为android:showAsAction=ifRoom时,何时才显示在溢出菜单中(或者干脆就不显示出来),代码逻辑可以参考ActionMenuPresenter.flagActionItems()方法,这里就不贴出来了; 溢出菜单按钮的实现类为OverflowMenuButton,后面会重点进行介绍,这里先记住它就是溢出菜单按钮吧。

溢出菜单按钮(OverflowMenuButton)什么时候放置到ActionBar上的呢?从android中ActionBar的源代码分析(二)我们可以看出,系统在创建菜单时,会调用ActionMenuPresenter的updateMenuView()方法,我们看一下这个方法的实现逻辑:

    @Override
    public void updateMenuView(boolean cleared) {
        final ViewGroup menuViewParent = (ViewGroup) ((View) mMenuView).getParent();
        if (menuViewParent != null) {
<span style="white-space:pre">	</span>    // 使用ActionBar的淡出淡入效果,其实系统本身并没有启用该效果
            ActionBarTransition.beginDelayedTransition(menuViewParent);
        }
        super.updateMenuView(cleared);  //使用父类的方法,构建ActionBar的按钮并添加到ActionMenuView上

        ((View) mMenuView).requestLayout();
<span style="white-space:pre">	</span>//判断菜单是否配置了ActionProvider,如果有则设置ActionProvider的子菜单侦听事件
        if (mMenu != null) {
            final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
            final int count = actionItems.size();
            for (int i = 0; i < count; i++) {
                final ActionProvider provider = actionItems.get(i).getActionProvider();
                if (provider != null) {
                    provider.setSubUiVisibilityListener(this);
                }
            }
        }

        final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ?
                mMenu.getNonActionItems() : null;
<span style="white-space:pre">	</span>//判断是否存在溢出菜单
        boolean hasOverflow = false;
        if (mReserveOverflow && nonActionItems != null) {
            final int count = nonActionItems.size();
            if (count == 1) {
                hasOverflow = !nonActionItems.get(0).isActionViewExpanded();   //如果只有一个菜单按钮,并且该菜单按钮是个可扩展按钮,则不显示溢出菜单按钮
            } else {
                hasOverflow = count > 0;
            }
        }
<span style="white-space:pre">	</span>//如果需要显示溢出菜单,则初始化溢出菜单按钮,并添加到ActionMenuView中
        if (hasOverflow) {
            if (mOverflowButton == null) {
                mOverflowButton = new OverflowMenuButton(mSystemContext);
            }
            ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
            if (parent != mMenuView) {
                if (parent != null) {
                    parent.removeView(mOverflowButton);
                }
                ActionMenuView menuView = (ActionMenuView) mMenuView;
                menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams());
            }
        } else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) {
            ((ViewGroup) mMenuView).removeView(mOverflowButton);
        }

        ((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow);
    }
这段代码首先是设置显示ActionBar的淡出淡入效果,从类ActionBarTransition的代码中可以看出,淡出淡入的效果受TRANSITIONS_ENABLED的控制,而TRANSITIONS_ENABLED是等于false的,而且也没发现在哪能设置这个变量的值,所以按照目前来看,ActionBar的淡出淡入效果是没有启用的;然后调用父类(BaseMenuPresenter)的updateMenuView()方法构建ActionBar的菜单按钮并添加到ActionMenuView 上,接着判断菜单是否配置启用了ActionProvider,如果启用了,就设置侦听其子菜单可见行改变的事件;最后判断是否显示溢出菜单,如果显示溢出菜单则调用溢出菜单按钮的初始化方法,并把它添加到ActionMenuView上显示出来;这样溢出菜单按钮就完成了整个的构建过程;

溢出菜单弹出执行过程分析

溢出菜单按钮点击以后,就会弹出下拉菜单来,这个过程在代码层次上具体是怎么实现的呢?这就需要我们看一下类OverflowMenuButton的具体实现了,OverflowMenuButton继承于类ImageButton,也就是说它实际就是一个图片按钮;我们先看一下OverflowMenuButton的构造方法吧

        public OverflowMenuButton(Context context) {
            super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
<span style="white-space:pre">	</span>    //设置控件可点击、可设置焦点、可用和可见性
            setClickable(true);
            setFocusable(true);
            setVisibility(VISIBLE);
            setEnabled(true);
<span style="white-space:pre">	</span>    //侦听控件本身的touch事件
            setOnTouchListener(new ForwardingListener(this) {
                @Override
                public ListPopupWindow getPopup() {
                    if (mOverflowPopup == null) {
                        return null;
                    }

                    return mOverflowPopup.getPopup();
                }

                @Override
                public boolean onForwardingStarted() {   // touch事件转发开始后,显示溢出菜单
                    showOverflowMenu();
                    return true;
                }

                @Override
                public boolean onForwardingStopped() {   // 溢出菜单显示后再次touch该控件,则隐藏溢出菜单
                    // Displaying the popup occurs asynchronously, so wait for
                    // the runnable to finish before deciding whether to stop
                    // forwarding.
                    if (mPostedOpenRunnable != null) {
                        return false;
                    }

                    hideOverflowMenu();
                    return true;
                }
            });
        }
OverflowMenuButton的构造方法,首先设置控件可点击、可设置焦点、可用和可见性,然后设置侦听控件的触摸事件,这里用到了ListPopupWindow.ForwardingListener类,该类其实是实现了View.OnTouchListener接口的,有几个方法需要重写:

  • onForwardingStarted()表示当手指在触摸溢出菜单按钮时回调该方法,这里是执行了showOverflowMenu()方法,按照字面的意思应该就是显示溢出菜单了,至于代码实现如何,一会再进行分析;
  • onForwardingStopped()表示当溢出菜单仍然显示,再次触摸溢出菜单按钮时回调该方法,这里首先判断mPostOpenRunnable是否为空,也即是否采用了Post Runnable的处理方式,如果没有则执行hideOverflowMenu()方法,按照字面的意思就是隐藏溢出菜单,至于代码实现如何,一会再进行分析;
  • getPopup()表示获取弹出菜单窗口,也即指定需要控制的弹出窗口,这里设置为溢出菜单按钮关联的PopupWindow
类OverflowMenuButton也重写了View的performClick()方法,代码如下:
        @Override
        public boolean performClick() {
            if (super.performClick()) {
                return true;
            }

            playSoundEffect(SoundEffectConstants.CLICK);
            showOverflowMenu();
            return true;
        }
代码很简单,就是先判断是否父类的performClick()方法的返回值是否为true,如果为true则退出,换句话讲就是判断外部调用的onClick的侦听事件是否返回true,如果没有设置onClick事件的侦听或者侦听回调方法返回值为false,则继续执行后面的showOverflowMenu()方法,本例中由于没有侦听OverflowMenuButton的onClick事件,因此必然要走showOverflowMenu()方法。
从上面分析可以看出,showOverflowMenu()方法是咱们分析溢出菜单显示的关键,那我们就来看一下这个方法的实现逻辑吧
    public boolean showOverflowMenu() {
        if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
                mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {
            OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
            mPostedOpenRunnable = new OpenOverflowRunnable(popup);
            // Post this for later; we might still need a layout for the anchor to be right.
            ((View) mMenuView).post(mPostedOpenRunnable);

            // ActionMenuPresenter uses null as a callback argument here
            // to indicate overflow is opening.
            super.onSubMenuSelected(null);

            return true;
        }
        return false;
    }
代码很简单,首先判断溢出菜单是否已经显示,如果没有显示,则实例化类OverflowPopup和OpenOverflowRunnable,并延后执行OpenOverflowRunnable中run()方法,最后调用父类的onSubMenuSelected()方法。这里的类OverflowPopup是菜单弹出的辅助类,继承于类MenuPopupHelper,负责管理弹出窗体(PopupWindow)的生命周期;而类OpenOverflowRunnable负责PopupWindow的显示,我们看一下OpenOverflowRunnable的代码逻辑:
    private class OpenOverflowRunnable implements Runnable {
        private OverflowPopup mPopup;

        public OpenOverflowRunnable(OverflowPopup popup) {
            mPopup = popup;
        }

        public void run() {
            mMenu.changeMenuMode();
            final View menuView = (View) mMenuView;
            if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
                mOverflowPopup = mPopup;
            }
            mPostedOpenRunnable = null;
        }
    }
我们主要看run()方法,在该方法中,首先调用MenuBuilder.changeMenuMode()方法切换菜单模式,也就是说如果菜单已经弹出则隐藏,否则就弹出显示;接着调用OverflowPopup的tryShow()方法弹出溢出菜单窗体。也许有朋友就问,MenuBuilder.changeMenuMode()方法不是已经显示过一次溢出菜单了吗,这里再次显示会不会重复显示呢?当然不会,系统通过设置变量mPostedOpenRunnable是否为空来进行区分,保证只会执行一次显示溢出菜单窗体的代码。
OverflowPopup.tryShow()方法又是如何显示溢出菜单窗体的呢?查找类OverflowPopup并没有tryShow()方法,那么调用的应该就是父类(MenuPopupHelper)的tryShow()方法了,代码如下:
   public boolean tryShow() {
        mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
        mPopup.setOnDismissListener(this);
        mPopup.setOnItemClickListener(this);
        mPopup.setAdapter(mAdapter);
        mPopup.setModal(true);

        View anchor = mAnchorView;
        if (anchor != null) {
            final boolean addGlobalListener = mTreeObserver == null;
            mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
            if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
            anchor.addOnAttachStateChangeListener(this);
            mPopup.setAnchorView(anchor);
            mPopup.setDropDownGravity(mDropDownGravity);
        } else {
            return false;
        }

        if (!mHasContentWidth) {
            mContentWidth = measureContentWidth();
            mHasContentWidth = true;
        }

        mPopup.setContentWidth(mContentWidth);
        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
        mPopup.show();
        mPopup.getListView().setOnKeyListener(this);
        return true;
    }
在这个代码中,首先是实例化ListPopupWindow,然后对这个ListPopupWindow对象进行各种属性赋值操作,最后调用show方法显示出来。这里的类ListPopupWindow通俗来讲就是一个包含一个ListView的PopupWindow,其具体的用法百度上有一大堆,有兴趣的朋友可以研究一下哈,这里就不过多赘述。使用ListPopupWindow时,有三个方法要注意:
  • setDismissListener() 负责侦听弹出窗体关闭的事件;这里把this传入,也就是说OverflowPopup的父类MenuPopupHelper是实现了接口PopupWindow.OnDismissListener的,也即实现了接口方法onDismiss()的,关于onDismiss()方法,稍后在分析溢出菜单隐藏时再进行介绍;
  • setOnItemClickListener() 负责侦听弹出窗体的菜单项点击事件;这里把this传入,也就是说OverflowPopup的父类MenuPopupHelper是实现了接口AdapterView.OnItemClickListener的,也就是实现了接口方法onItemClick()的,在这个方法中,会调用MenuBuilder的performItemAction()方法,这个方法在上一章已经进行过介绍,有兴趣的朋友可以看android中ActionBar的源代码分析(三)
  • setAdapter() 这个就是设置ListView的数据适配类;这里传入的是mAdapter,其实现类为MenuPopupHelper.MenuAdapter,实现代码如下:
    private class MenuAdapter extends BaseAdapter {
        private MenuBuilder mAdapterMenu;
        private int mExpandedIndex = -1;

        public MenuAdapter(MenuBuilder menu) {
            mAdapterMenu = menu;
            findExpandedIndex();
        }

        public int getCount() {
            ArrayList<MenuItemImpl> items = mOverflowOnly ?
                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
            if (mExpandedIndex < 0) {
                return items.size();
            }
            return items.size() - 1;
        }

        public MenuItemImpl getItem(int position) {
            ArrayList<MenuItemImpl> items = mOverflowOnly ?
                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
            if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
                position++;
            }
            return items.get(position);
        }

        public long getItemId(int position) {
            // Since a menu item's ID is optional, we'll use the position as an
            // ID for the item in the AdapterView
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
            }

            MenuView.ItemView itemView = (MenuView.ItemView) convertView;
            if (mForceShowIcon) {
                ((ListMenuItemView) convertView).setForceShowIcon(true);
            }
            itemView.initialize(getItem(position), 0);
            return convertView;
        }

        void findExpandedIndex() {
            final MenuItemImpl expandedItem = mMenu.getExpandedItem();
            if (expandedItem != null) {
                final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
                final int count = items.size();
                for (int i = 0; i < count; i++) {
                    final MenuItemImpl item = items.get(i);
                    if (item == expandedItem) {
                        mExpandedIndex = i;
                        return;
                    }
                }
            }
            mExpandedIndex = -1;
        }

        @Override
        public void notifyDataSetChanged() {
            findExpandedIndex();
            super.notifyDataSetChanged();
        }
    }
我们重点看getCount()和getView()方法即可,在getCount()方法中,获取ActionBar的不可见菜单项,然后判断在这些不可见菜单项中是否有可扩展折叠菜单项,如果有则排除掉,换句话讲就是可扩展折叠的菜单项是不会显示在溢出菜单中的;在getView()方法中通过inflater布局文件framework\data\res\layout\popup_menu_item_layout.xml来创建视图,并对菜单项进行初始化操作,下面是popup_menu_item_layout.xml的内容
<com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/dropdownListPreferredItemHeight"
    android:minWidth="196dip"
    android:paddingEnd="16dip">
    
    <!-- Icon will be inserted here. -->
    
    <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
    <RelativeLayout
        android:layout_width="0dip"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginStart="16dip"
        android:duplicateParentState="true">
        
        <TextView 
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentStart="true"
            android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
            android:singleLine="true"
            android:duplicateParentState="true"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal"
            android:textAlignment="viewStart" />

        <TextView
            android:id="@+id/shortcut"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/title"
            android:layout_alignParentStart="true"
            android:textAppearance="?android:attr/textAppearanceSmallPopupMenu"
            android:singleLine="true"
            android:duplicateParentState="true"
            android:textAlignment="viewStart" />

    </RelativeLayout>

    <!-- Checkbox, and/or radio button will be inserted here. -->
    
</com.android.internal.view.menu.ListMenuItemView>
可以看到,其实每一个溢出菜单的菜单项的实现类为ListMenuItemView,它继承于LinearLayout;ListMenuItemView包含三个子视图:一个ImageView,负责显示菜单图标;一个TextView,负责显示菜单标题;一个TextView,负责显示菜单的快捷方式,默认情况下快捷方式是不显示的。其中两个TextView是在布局文件中列出,还有一个ImageView,是通过代码来创建的,可以看一下ListMenuItemView的setIcon()方法如下:
    public void setIcon(Drawable icon) {
<span style="white-space:pre">	</span>//判断图标是否需要显示
        final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
        if (!showIcon && !mPreserveIconSpacing) {
            return;
        }
        
        if (mIconView == null && icon == null && !mPreserveIconSpacing) {
            return;
        }
        //如果需要显示图标,则创建控件并添加进来
        if (mIconView == null) {
            insertIconView();
        }
        //设置可见性
        if (icon != null || mPreserveIconSpacing) {
            mIconView.setImageDrawable(showIcon ? icon : null);

            if (mIconView.getVisibility() != VISIBLE) {
                mIconView.setVisibility(VISIBLE);
            }
        } else {
            mIconView.setVisibility(GONE);
        }
    }
声明一下,setIcon()方法是在ListMenuItemView.initialize()方法中调用的,而ListMenuItemView.initialize()又是由类MenuPopupHelper.MenuAdapter在方法getView()中调用的;
在setIcon()方法中,首先判断图标是否需要显示,如果不需要显示则直接退出,否则就创建ImageView来显示图标,最后设置ImageView的可见性,这里我们注意到,菜单图标的可见性受mItemData.shouldShowIcon()的控制,这里的mItemData的实现类为MenuItemImpl,我们看一下MenuItemImpl.shouldShowIcon()的实现代码:
    public boolean shouldShowIcon() {
        return mMenu.getOptionalIconsVisible();
    }
很简单,就是直接调用MenuBuilder.getOptionalIconsVisible()的方法进行判断,而getOptionalIconsVisible()是直接返回mOptionalIconsVisible的值,mOptionalIconsVisible的默认值为false,它是通过setOptionalIconsVisible()设置进来的,不幸的是setOptionalIconsVisible()的方法修饰符为Internal,外部是无法访问的,只能通过反射的方式来修改;这就是为什么在默认情况下,溢出菜单显示的菜单项只有文字没有图标的原因了!

溢出菜单隐藏执行过程分析

上面提到ListPopupWindow是一个包含ListView的PopupWindow,OverflowPopup在创建ListPopupWindow时,调用ListPopupWindow.setDismiss()去侦听弹出窗体关闭的事件,而传入参数为this,也就是OverflowPopup的父类MenuPopupHelper是实现了接口PopupWindow.OnDismissListener的,也即实现了接口方法onDismiss()的,onDismiss()方法的代码如下:
    public void onDismiss() {
        mPopup = null;
        mMenu.close();
        if (mTreeObserver != null) {
            if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
            mTreeObserver.removeGlobalOnLayoutListener(this);
            mTreeObserver = null;
        }
        mAnchorView.removeOnAttachStateChangeListener(this);
    }
这里调用了MenuBuilder.close()方法进行关闭弹出菜单操作,下面是MenuBuilder.close()方法的实现代码:
    public void close() {
        close(true);
    }

    final void close(boolean allMenusAreClosing) {
        if (mIsClosing) return;

        mIsClosing = true;
        for (WeakReference<MenuPresenter> ref : mPresenters) {
            final MenuPresenter presenter = ref.get();
            if (presenter == null) {
                mPresenters.remove(ref);
            } else {
                presenter.onCloseMenu(this, allMenusAreClosing);
            }
        }
        mIsClosing = false;
    }
其实就是调用了ActionMenuPresenter.onCloseMenu()方法执行关闭操作:
    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
        dismissPopupMenus();
        super.onCloseMenu(menu, allMenusAreClosing);
    }

    public boolean dismissPopupMenus() {
        boolean result = hideOverflowMenu();
        result |= hideSubMenus();
        return result;
    }
可以看到执行关闭菜单的操作,都是执行了hideOverflowMenu()方法来实现的:
    public boolean hideOverflowMenu() {
        if (mPostedOpenRunnable != null && mMenuView != null) {
            ((View) mMenuView).removeCallbacks(mPostedOpenRunnable);
            mPostedOpenRunnable = null;
            return true;
        }

        MenuPopupHelper popup = mOverflowPopup;
        if (popup != null) {
            popup.dismiss();
            return true;
        }
        return false;
    }

hideOverflowMenu()方法实现逻辑很简单,其实就是调用了PopupWindow的dismiss方法进行的。

关于ActionBar的OverflowMenu的执行过程分析到此为止,如有需要交流,欢迎留言!

手把手教你学Simulink——基于Simulink的无感FOC(滑模观测器+PLL)实战 本文详细介绍了基于Simulink的无感FOC(滑模观测器+PLL)实现方法。主要内容包括:1)SMO+PLL原理精讲,阐述滑模观测器核心思想和PLL的作用;2)系统架构全景图展示;3)Simulink建模全流程,从基础FOC框架到SMO和PLL模块的实现;4)关键参数整定指南和工程实践要点;5)仿真结果分析及常见问题解决方案。该方法可有效替代机械传感器,降低成本并提高可靠性,适用于空调压缩机、电动汽车水泵等工业场景。文章还提供了详细的调试建议和动手实践指导。 阅读详情

相关推荐

新疆地形数据下载:30米、12.5米、5米DEM地形数据

新疆是我国陆地面积最大的省级行政区,总面积达166万平方公里。新疆的地形也十分的复杂,新疆的地形呈山脉与盆地相间排列,盆地被高山环抱,,俗称“三山夹两盆”。三山指阿尔泰山、昆仑山、天山,两盆是指塔里木盆地和准噶尔盆地。 对精度要求不高的话,可以直接使用图新地球下载 新疆30米地形数据 大小:9.26GB 来自ASTER v3的新疆30米地形数据 30米地形数据下载 新疆12.5米地形数据 12.5米DEM数据由于精度比较高,一般不会用到全省的数据,通常用的是一个地区的,因此,可以单独分

LocaSpace的博客 3495

android开发action bar中menu菜单action overflow问题

最近在学习action bar的内容,是直接参考android官网的资料学习。       参考http://developer.android.com/training/basics/actionbar/adding-buttons.html 文档学习action bar的开发过程中,遇到一个问题,经过搜索以及查阅更详细文档,得到解答,现以记录。       根据原文的描述,根据下面配置使用

行者无疆的专栏 7231

SPSS&Mplus—共同方法偏差(Common Method Bias)控制与检验

共同方法偏差(Common Method Bias)的控制方法:程序控制(Procedural)和统计控制(Statistical)。

m0_54401011的博客 1万+

【Android 应用开发】 ActionBar 基础

作者 : 万境绝尘 (octopus_truth@163.com) 转载请注明出处 :http://blog.youkuaiyun.com/shulianghan/article/details/39204393 示例代码下载 : -- GitHub :https://github.com/han1202012/Octopus_ActionBar.git -- 优快云 :http://download....

f059074251的专栏 236

通过声音识别鸟类

根据野生鸟类的外表来识别它是一回事。仅仅根据声音来识别同一只鸟是另一回事。除非你是一个熟练的观鸟者,通过声音识别鸟类可能相当具有挑战性德国马尔堡大学的一组数学、计算机科学和生物学研究人员设计了一种快速识别鸟类和监测当地生物多样性的方法。他们使用连接到 NVIDIA 的便携式设备拍摄的录音根据研究人员的说法是一个边缘人工智能系统,“基于分布式系统中运行的嵌入式边缘设备,能够对森林中记录的声景进行高效、连续的评估。”要了解更多信息,请参阅。

分享AI前沿科技 1680

小白学习图像处理6——Canny边缘检测算法原理

目录结构一、高斯滤波二、梯度计算1、原理2、代码如下三、非极大值抑制三、双阈值检测四、matlab 的 edge函数五、总结 Canny边缘检测算法主要步骤:高斯滤波、梯度计算、非极大值抑制和双阈值检测。 一、高斯滤波   使用高斯滤波的目的是平滑图像,滤除图像中的部分噪声(因为微分算子对噪声很敏感)。高斯滤波具体办法是生成一个高斯模板,使用卷积进行时域滤波: img = im2double(im...

我有两颗糖 7791

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

转载请注明出处:http://blog.youkuaiyun.com/qinjuning    Android3.0 以后 Menu相关做了较大改变。ActionBar作为新的Menu形式粉墨登场了。 常见的Menu或ActionBar有这四种:

qinjuning、lets go 1万+

gm/Id 设计方法

本文介绍gm/Id方法的具体实现。

maxwell2ic的博客 4万+

Android记录23-关于actionbar中overflow menu(溢出菜单)中的一些问题

总之啊,家里没矿的同学们,如果你们想以后的日子过得好一些,多想想你们的业余时间怎么安排吧;技术方面的提升肯定是重中之重,但是技术外的一些“软实力”也不能完全忽视,很多时候升职确实是因为你的技术足够强,但也与你的“软实力”密切相关在这我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅并给下属员工学习的精品资料。

2401_84413396的博客 944

用miniconda建立PyTorch、Keras、TensorFlow三个环境

如果还没有安装Miniconda,请从[Miniconda官网](https://docs.conda.io/en/latest/miniconda.html)下载合适的版本并进行安装。如果遇到问题,可以通过编辑`~/.condarc`文件来临时禁用某个源,或者通过`conda config --remove channels`命令来移除配置的镜像源。要切换到不同的环境,先使用`conda deactivate`命令退出当前环境,再用`conda activate 环境名称`命令激活另一个环境。

数字人生 2464

第12步 支持向量机(SVM)

搭建SVM

Jet4505的博客 1051

具有多选功能的spinner自定义控件

概述当我们要做单选功能的时候,我们会很自然的想到Spinner,它可以在一个集合中选择一个我们需要的值。但是有时候我们需要在一个集合中选择多个值,这个时候Spinner就不能满足需求。此时可以根据自己的需要来实现类似于Spinner效果的多选控件。效果图实现分析需要实现的效果是点击一个文本后弹出一个多选列表,在点击之后选择、取消选择,点击确定之后设置文本。这个文本框就用TextView,让它支持点击

程序员yqy的博客 7859

MOS管基础知识及应用电路Multisim仿真

本文系统介绍了MOS管的基础知识及其在电子电路中的典型应用。首先详细解析了MOS管的基本结构、分类和工作原理,包括NMOS、PMOS及CMOS的特性差异。重点阐述了MOS管的三种放大组态电路(共源、共漏、共栅)及其小信号模型分析。随后通过Multisim仿真验证了MOS管在防反接电路、开关电路、放大电路、逻辑门电路、电平转换电路和开关电源(BUCK、BOOST、BUCK-BOOST)等应用中的实际表现。文章还深入探讨了自给偏压和分压式偏置电路的设计要点。全文通过理论分析与仿真实验相结合的方式,全面展示了MO

XU157303764的博客 1485

Android ActionBar的源代码分析(一)

ActionBar是android的一个非常重要开发组件,在很多商业应用中到处可见,也是很多android开发人员必须熟练掌握的开发技术,下面就从源码角度来分析ActionBar的实现过程。 从哪里开始呢? 我们回忆一下在Activity中获取ActionBar的方法为getActionBar(),那就从getActionBar()开始研究吧! 打开getActionBar()的代码实现如下

呼啸而过的专栏 5041

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Android ActionBar的源代码分析(二)

前面已经对ActionBar的初始换过程进行比较详细的分析,没有看过的朋友可以移步android中ActionBar的源代码分析(一)。本章接着对ActionBar的运行机制进行分析。

呼啸而过的专栏 2532

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Android ActionBar的源代码分析(三)

上一篇已经对ActionBar菜单构造过程进行比较详细的分析,没有看过的朋友可以移步android中ActionBar的源代码分析(二)。本章接着对ActionBar菜单的执行过程进行分析。 在介绍ActionBar菜单的执行过程之前,首先我们需要了解android的消息处理机制,我们知道activity的activity等组件和view控件都是运行在主线程上的,这个主线程我们也称为UI线程,U

呼啸而过的专栏 2552

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

安卓9.0ActionBar点击无响应事件

安卓9.0ActionBar点击无响应事件

loveyouloveyourcat的博客 1957

Android开发之ActionBar结合Fragment的导航功能的使用(源代码分享)

标签在操作栏方便用户去探索,在你的应用程序在不同视图之间切换。ActionBar提供的标签是最理想的选择,因为他们适应不同的屏幕尺寸。一旦你确定了Fragment出现在布局里,添加标签的步骤如下:一:继承ActionBar.TabListener接口,控制哪个标签被选中,进而切换布局;二:对于每一个您想要添加标签,实例化一个ActionBar,选项卡调用setTabListener TabList

林泓成的专栏 3172

android ActionBar-PullToRefresh 下拉刷新的使用方法

Shilslas 这个最终效果,  图片来自http://a.code4app.com/android/ActionBar-PullToRefresh/524f9a156803faab3c000000 由于对于导包不是很了解,这个下拉刷新花费了我很多时间。 其实很简单,也就是两个类,首先你要下载ActionBar-PullToRefresh    点击打开链接 然后还要下载

what is name 5180

Attempt to invoke virtual method 'void android.app.ActionBar.setTitle的解决方法

在安卓4.4.2的关于蓝牙开发的一个demo,

jasonkent27的专栏 1万+

直播app源代码,android中actionbar的显示操作

直播app源代码,android中actionbar的显示操作相关的代码 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <!--这个位置的话是我们的的菜单资源文件--> <item an

云豹网络科技 181

关于fragment、ActionBar与ViewPager的一些总结

今天花了大半天去研究ActionBar获取指针为空,fragment嵌套失败等问题,在此做一些总结,以免之后再犯错: 今天主要工作为在atyA中填充fragmentA,而在fragmentA中初始化ActionBar与ViewPager,而ViewPager实现FragmentPagerAdapter来填充内容 分别使用了: import android.support.v4.app

shw372029857的博客 1187

Android ActionBar详解(二)

最近一直在研究Android ActionBar和Fragment,参看Google的官方文档和网上一些demo源代码,记录一下主要的知识点,也跟大家分享一下! 具体内容请参看链接:http://developer.android.com/guide/topics/ui/actionbar.html 一、添加Action Items 在Activity或者Fragment 的 onC

Ricky 4714

Android actionBar与Fragment结合使用Demo

本文介绍ActionBar与Fragment结合使用的一个实例,ActionBar是一个标识应用程序和用户位置的窗口功能,并且给用户提供操作和导航模式。  Action bar的主要用途是:         1.  提供一个用于识别应用程序的标示和用户的位置的专用空间。          这个空间的左边是应用的图标或logo,以及Activity的标题。但是,如果

红日 2254

[android ui]ActionBar的Action图标区添加

ActionBar的隐藏和现实 ActionBar bar = getActionBar(); bar.hide();  //隐藏Action Bar bar.show(); //显示Action Bar ActionBar的action图标区 ActionBar的右侧就是action图标区域,如下图所示 这是ActionBar的menu区域,作为options

超级方的专栏 1475

Android技术——视图切换(一)利用ActionBar实现Tab导航

一、滑动菜单有两种实现方法:借助ActionBar;借助FragmentTabHost 二、借助ActionBar实现滑动菜单

YongYu_IT的专栏 1393
上一篇: Android ActionBar的源代码分析(三)
下一篇: Android RxJava使用介绍(一) Hello World
呼啸而过11
博客等级 码龄19年 120粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值