Android开发Android开发Android技术知识

Android 7.0长按Actionbar的菜单选项显示Toa

2018-08-24  本文已影响7人  柒里夜

最近遇到要消除长按 Actionbar 上的菜单项会在选项底部出现一个 Toast 提示的需求,所以在网上查了很久解决方法,现配合源码简单整理一下。Actionbar 对于开发者来说想必就不用过多介绍了,就是下面这个东东:


Actionbar

在哪实现?

知道如何使用 Actionbar 的人肯定知道是在 activity 中的 onCreateOptionsMenu(Menu menu) 方法中将自己定义的 menu 选项加载到 menu 上等等。但是 menu 和其上的 item 到底是在哪里定义的?

通过在源码查找发现,与 menu 有关的类都在 /frameworks/base/core/java/com/android/internal/view/menu 目录下(此目录针对 Android 7.0)。

ActionMenuItem.java      ContextMenuBuilder.java  ListMenuItemView.java   MenuHelper.java       MenuView.java
ActionMenuItemView.java  ExpandedMenuView.java    ListMenuPresenter.java  MenuItemImpl.java     ShowableListMenu.java
ActionMenu.java          IconMenuItemView.java    MenuAdapter.java        MenuPopupHelper.java  StandardMenuPopup.java
BaseMenuPresenter.java   IconMenuPresenter.java   MenuBuilder.java        MenuPopup.java        SubMenuBuilder.java
CascadingMenuPopup.java  IconMenuView.java        MenuDialogHelper.java   MenuPresenter.java

这有很多个类,通过类名和验证可以找到 actionbar menu 中 item 对应的视图类,即 ActionMenuItemView.java。所以这个长按 item 显示 Toast 的提示一定是在这个类中实现的。

//frameworks\base\core\java\com\android\internal\view\menu\ActionMenuItemView.java

    @Override
    public boolean onLongClick(View v) {
        if (hasText()) {
            // Don't show the cheat sheet for items that already show text.
            return false;
        }

        final int[] screenPos = new int[2];
        final Rect displayFrame = new Rect();
        getLocationOnScreen(screenPos);
        getWindowVisibleDisplayFrame(displayFrame);

        final Context context = getContext();
        final int width = getWidth();
        final int height = getHeight();
        final int midy = screenPos[1] + height / 2;
        int referenceX = screenPos[0] + width / 2;
        if (v.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) {
            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
            referenceX = screenWidth - referenceX; // mirror
        }
        // 创建 Toast
        Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
        if (midy < displayFrame.height()) {
            // Show along the top; follow action buttons
            cheatSheet.setGravity(Gravity.TOP | Gravity.END, referenceX,
                    screenPos[1] + height - displayFrame.top);
        } else {
            // Show along the bottom center
            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
        }
        cheatSheet.show();
        return true;
    }

果然,在 ActionMenuItemView 中的 onLongClick() 中,先是判断 item 是否已经显示了 text,若是的话则直接返回 false。若 text 没有显示的话,则根据 item 在屏幕中的位置来在其下方或屏幕底部显示一个 Toast 提示,而 Toast 显示的内容正是该 item 的 title。也就是下面在 xml 文件中所设置的 android:title 属性。

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/menu_add_contact"
        android:icon="@drawable/custom_drawable"
        android:title="@string/custom_title"
        app:showAsAction="ifRoom" />
    ...
</menu>

如何修改?

若是要修改这一行为有很多方式:

本文仅查看了长按 menu 选项出现 Toast 提示实现的部分,详细的完整 actionbar 框架网上有很多相关的介绍,感兴趣可以自己研究一下。

上一篇下一篇

猜你喜欢

热点阅读