android长按呼出菜单,Android 7.0长按Actionbar的菜单选项显示Toast提示的实现

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

00a125975ae9

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 属性。

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

android:id="@+id/menu_add_contact"

android:icon="@drawable/custom_drawable"

android:title="@string/custom_title"

app:showAsAction="ifRoom" />

...

如何修改?

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

系统层:对于可以访问和修改源码的开发者,可以直接修改 ActionMenuItemView.java 中的实现,但要注意,这只会对继承系统 Activity.java 的 activity 有效,对于继承了其他如 v7 包中的 AppCompatActivity.java 的 activity 就无法生效。而且修改系统层的代码对于 app 来说只会在这一个系统中生效,若是安装在别的源码编译的系统中则会使用它们自己的实现方式。

应用层:若是在 app 中直接修改则不会有在系统中修改的许多问题。可以自己定义一个 actionbar 或者自己定义一个 view 做为 item 的 view,然后在自定义的 view 中做点击处理。相关修改可以查看Hiding of the Toast for long press on actionBar item。

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值