【发布时间】:2017-03-22 14:47:58
【问题描述】:
我想要做的是显示一个 PopupWindow 指向工具栏上的溢出图标(三个点)。所以我需要使用图标的 id 获取对 View 对象的引用。但是id是什么?
PopupWindow 用于告诉用户溢出菜单中添加了新条目。并建议用户查看。
【问题讨论】:
标签: android
我想要做的是显示一个 PopupWindow 指向工具栏上的溢出图标(三个点)。所以我需要使用图标的 id 获取对 View 对象的引用。但是id是什么?
PopupWindow 用于告诉用户溢出菜单中添加了新条目。并建议用户查看。
【问题讨论】:
标签: android
你应该创建按钮 id
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="overflowActionButton"/>
</resources>
然后创建按钮样式
<style name="Widget.ActionButton.Overflow" parent="Widget.AppCompat.ActionButton.Overflow">
<item name="android:id">@id/overflowActionButton</item>
</style>
并在主题中添加此样式
<style name="Theme.App" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="actionOverflowButtonStyle">@style/Widget.ActionButton.Overflow</item>
</style>
最后你应该通过 id 找到按钮视图
activity.findViewById(R.id.overflowActionButton)
做你想做的事
【讨论】:
溢出菜单项没有资源 ID。我通过遍历工具栏找到了溢出视图。调试器显示的 id 为 -1,而 Hierarchy Viewer 没有显示资源 id。
这是我如何找到没有资源 ID 的溢出视图:
/**
* Get the OverflowMenuButton.
*
* @param activity
* the Activity
* @return the OverflowMenuButton or {@code null} if it doesn't exist.
*/
public static ImageView getOverflowMenuButton(Activity activity) {
return findOverflowMenuButton(activity, findActionBar(activity));
}
static ImageView findOverflowMenuButton(Activity activity, ViewGroup viewGroup) {
if (viewGroup == null) {
return null;
}
ImageView overflow = null;
for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
View v = viewGroup.getChildAt(i);
if (v instanceof ImageView && (v.getClass().getSimpleName().equals("OverflowMenuButton") ||
v instanceof ActionMenuView.ActionMenuChildView)) {
overflow = (ImageView) v;
} else if (v instanceof ViewGroup) {
overflow = findOverflowMenuButton(activity, (ViewGroup) v);
}
if (overflow != null) {
break;
}
}
return overflow;
}
static ViewGroup findActionBar(Activity activity) {
try {
int id = activity.getResources().getIdentifier("action_bar", "id", "android");
ViewGroup actionBar = null;
if (id != 0) {
actionBar = (ViewGroup) activity.findViewById(id);
}
if (actionBar == null) {
return findToolbar((ViewGroup) activity.findViewById(android.R.id.content).getRootView());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
static ViewGroup findToolbar(ViewGroup viewGroup) {
ViewGroup toolbar = null;
for (int i = 0, len = viewGroup.getChildCount(); i < len; i++) {
View view = viewGroup.getChildAt(i);
if (view.getClass() == android.support.v7.widget.Toolbar.class ||
view.getClass().getName().equals("android.widget.Toolbar")) {
toolbar = (ViewGroup) view;
} else if (view instanceof ViewGroup) {
toolbar = findToolbar((ViewGroup) view);
}
if (toolbar != null) {
break;
}
}
return toolbar;
}
调用getOverflowMenuButton(activity) 将在onCreate 中返回null,因为尚未布置溢出菜单。要在 onCreate 中获取溢出菜单,我做了以下操作:
findViewById(android.R.id.content).post(new Runnable() {
@Override public void run() {
ImageView overflow = getOverflowMenuButton(MainActivity.this);
}
});
【讨论】:
我找到了一个名为 TapTarget 的库和一个函数 TapTarget.forToolbarOverflow()。它提出了一个解决方案:https://github.com/KeepSafe/TapTargetView/blob/master/taptargetview/src/main/java/com/getkeepsafe/taptargetview/TapTarget.java#L96
它找到溢出视图的方式并不整洁,但应该是稳定的。
【讨论】:
androidx.appcompat.widget.Toolbar而不是原生的android.widget.Toolbar,它只取决于支持库版本,而不是Android版本。每次更新支持库时都可以轻松地测试这一点。
您想创建自定义DropDown 菜单吗? consider this "native" way
或在您的menu.xml 中使用android:showAsAction="never"。 showAsAction 属性 HERE 的文档。当MenuItems 之一设置never 值时,您将自动获得溢出的三点图标,这些MenuItems 将隐藏在那里
如果确实需要,您也可以尝试使用Hierarchy Viewer 来调查此 ID
【讨论】:
我没有使用昂贵且复杂的布局遍历来查找溢出菜单,而是通过使用 Toolbar 视图作为锚点并将重力设置为 Gravity,实现了在溢出菜单下显示 PopupWindow。END:
/**
* Sets the anchor view and shows the popup. In case of narrow display the menu items may be hidden in an overflow
* menu, in that case anchorView may be null and the popup will be anchored to the end of the toolbar.
*/
public void show(@Nullable View anchorView, @NonNull View toolbarView) {
if (anchorView == null) {
setDropDownGravity(Gravity.END);
setAnchorView(toolbarView);
} else {
setAnchorView(anchorView);
}
show();
}
【讨论】:
您可能在菜单资源中创建了一个菜单项 xml 以具有溢出按钮,因此您必须使用您在菜单 xml 中指定的溢出按钮项的 id
【讨论】: