我要做的是显示一个指向工具栏溢出图标(三个点)的 PopupWindow。因此,我需要获取具有该图标 id 的 View 对象的引用。但是这个 id 是什么呢?
PopupWindow 用于告诉用户溢出菜单中添加了新条目,并建议用户检查它。
PopupWindow 用于告诉用户溢出菜单中添加了新条目,并建议用户检查它。
你应该创建按钮的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
,层次结构查看器未显示任何资源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;
}
在onCreate
调用getOverflowMenuButton(activity)
会返回null
,因为溢出菜单还没有被布局。为了在onCreate
中获取溢出菜单,可以按照以下步骤进行操作:
findViewById(android.R.id.content).post(new Runnable() {
@Override public void run() {
ImageView overflow = getOverflowMenuButton(MainActivity.this);
}
});
不必使用昂贵且复杂的布局遍历来查找溢出菜单,我已经通过使用工具栏视图作为锚点并将重力设置为Gravity.END来实现在溢出菜单下方显示PopupWindow:
/**
* 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();
}
你想要创建自定义的DropDown
菜单吗?考虑使用这种“本地”的方式
或者在你的menu.xml
中使用android:showAsAction="never"
。关于showAsAction
属性的文档在这里。当其中一个MenuItem
设置了never
值时,你将自动获得溢出的三个点图标,并且这些MenuItem
将被隐藏在那里。
此外,如果确实需要,你也可以尝试使用Hierarchy Viewer来调查这个id。
androidx.appcompat.widget.Toolbar
而不是原生的android.widget.Toolbar
,它仅取决于支持库版本,而不是 Android 版本。这是每次更新支持库时都可以轻松测试的内容。 - devconsole