如何获取操作菜单中图标的位置?
How can I get the location of an icon in the action menu?
我正在为应用程序开发教程,我需要指向工具栏中的特定图标。
这是操作菜单的 XML 摘录:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item android:id="@+id/AbErase"
android:title="@string/Erase"
android:icon="@android:drawable/ic_delete"
android:orderInCategory="10"
app:showAsAction="ifRoom|collapseActionView" />
<item android:id="@+id/AbSuggest"
android:title="@string/Suggest"
android:icon="@mipmap/ic_lightbulb_outline_white_48dp"
android:orderInCategory="50"
app:showAsAction="ifRoom|collapseActionView" />
<item android:id="@+id/AbUndo"
android:title="@string/ActionBarUndo"
android:icon="@android:drawable/ic_menu_revert"
android:orderInCategory="51"
app:showAsAction="ifRoom|collapseActionView" />
...
这是我的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isBeingRestored = (savedInstanceState != null);
Toolbar scToolbar = (Toolbar) findViewById(R.id.Sc_toolbar);
setSupportActionBar(scToolbar);
scToolbar.post(new Runnable() {
@Override
public void run() {
if (!isBeingRestored) {
//View mErase = findViewById(R.id.AbErase);
View mErase = overflowMenu.getItem(0).getActionView();
int[] location = new int[2];
mErase.getLocationOnScreen(location);
eraseIconLeft = location[0];
}
}
}
View mErase = findViewById(R.id.AbErase);
mErase
设置为 null
,**** start EDIT **** 这并不奇怪AbErase 是 MenuItem 的 id,而不是 View 的 id。 **** 结束编辑 ****
View mErase = overflowMenu.getItem(0).getActionView();
location
设置为 (0, 24),这是错误的,因为工具栏中已经有徽标图标和标题。
如何获取工具栏中 AbErase
视图的绝对 X 坐标?
**** 编辑 ****
这是可以找到静态变量 overflowMenu
初始化的代码:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
actionBar.collapseActionView();
overflowMenu = menu;
isInitializedMenuItem = menu.findItem(R.id.AbInitialized);
isInitializedMenuItem.setChecked(isInitializeCbxChecked);
return super.onCreateOptionsMenu(menu);
}
在onCreate
方法还为时过早。视图尚未测量。覆盖 onPrepareOptionMenu()
并将您的代码放入其中。同时删除您的 Runnable,这是不必要的。
试试下面的代码片段
@Nullable
View getMenuItemView(Toolbar toolbar, @IdRes int menuItemId) throws IllegalAccessException,NoSuchFieldException {
Field mMenuView = Toolbar.class.getDeclaredField("mMenuView");
mMenuView.setAccessible(true);
Object menuView = mMenuView.get(toolbar);
Field mChildren = menuView.getClass() //android.support.v7.internal.view.menu.ActionMenuView
.getSuperclass() //android.support.v7.widget.LinearLayoutCompat
.getSuperclass() //android.view.ViewGroup
.getDeclaredField("mChildren");
mChildren.setAccessible(true);
View[] children = (View[]) mChildren.get(menuView);
for (View child : children) {
if (child.getId() == menuItemId) {
return child;
}
}
return null;
}
假设使用了 android.support.v7.widget。上面的方法将 return 一个与你的菜单项对应的视图。
View menuItemView = getMenuItemView(scToolbar,R.id.AbErase);
int x = menuItemView.getX();
int y = menuItemView.getY();
你有你的坐标。
编辑
经过更多研究后,我发现不需要反射。
在获取 menuItemView
之前,我们必须等待 Toolbar
完成其布局过程
scToolbar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
scToolbar.getViewTreeObserver().removeOnGlobalLayoutListener(this);
View menuItem = findViewById(R.id.AbErase);
if (menuItem != null) {
int[] location = new int[2];
menuItem.getLocationOnScreen(location);
int x = location[0]; //x coordinate
int y = location[1]; //y coordinate
}
}
});
上面的代码片段经测试可以工作,它可以放在任何方便的生命周期回调方法中。
编辑
在查看 activity 的源代码时,必须记住的关键是 View menuItem = findViewById(R.id.AbErase);
只能从 ViewTreeObserver.OnGlobalLayoutListener
、onGlobalLayout
回调中调用。
我正在为应用程序开发教程,我需要指向工具栏中的特定图标。
这是操作菜单的 XML 摘录:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item android:id="@+id/AbErase"
android:title="@string/Erase"
android:icon="@android:drawable/ic_delete"
android:orderInCategory="10"
app:showAsAction="ifRoom|collapseActionView" />
<item android:id="@+id/AbSuggest"
android:title="@string/Suggest"
android:icon="@mipmap/ic_lightbulb_outline_white_48dp"
android:orderInCategory="50"
app:showAsAction="ifRoom|collapseActionView" />
<item android:id="@+id/AbUndo"
android:title="@string/ActionBarUndo"
android:icon="@android:drawable/ic_menu_revert"
android:orderInCategory="51"
app:showAsAction="ifRoom|collapseActionView" />
...
这是我的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isBeingRestored = (savedInstanceState != null);
Toolbar scToolbar = (Toolbar) findViewById(R.id.Sc_toolbar);
setSupportActionBar(scToolbar);
scToolbar.post(new Runnable() {
@Override
public void run() {
if (!isBeingRestored) {
//View mErase = findViewById(R.id.AbErase);
View mErase = overflowMenu.getItem(0).getActionView();
int[] location = new int[2];
mErase.getLocationOnScreen(location);
eraseIconLeft = location[0];
}
}
}
View mErase = findViewById(R.id.AbErase);
mErase
设置为 null
,**** start EDIT **** 这并不奇怪AbErase 是 MenuItem 的 id,而不是 View 的 id。 **** 结束编辑 ****
View mErase = overflowMenu.getItem(0).getActionView();
location
设置为 (0, 24),这是错误的,因为工具栏中已经有徽标图标和标题。
如何获取工具栏中 AbErase
视图的绝对 X 坐标?
**** 编辑 ****
这是可以找到静态变量 overflowMenu
初始化的代码:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
actionBar.collapseActionView();
overflowMenu = menu;
isInitializedMenuItem = menu.findItem(R.id.AbInitialized);
isInitializedMenuItem.setChecked(isInitializeCbxChecked);
return super.onCreateOptionsMenu(menu);
}
在onCreate
方法还为时过早。视图尚未测量。覆盖 onPrepareOptionMenu()
并将您的代码放入其中。同时删除您的 Runnable,这是不必要的。
试试下面的代码片段
@Nullable
View getMenuItemView(Toolbar toolbar, @IdRes int menuItemId) throws IllegalAccessException,NoSuchFieldException {
Field mMenuView = Toolbar.class.getDeclaredField("mMenuView");
mMenuView.setAccessible(true);
Object menuView = mMenuView.get(toolbar);
Field mChildren = menuView.getClass() //android.support.v7.internal.view.menu.ActionMenuView
.getSuperclass() //android.support.v7.widget.LinearLayoutCompat
.getSuperclass() //android.view.ViewGroup
.getDeclaredField("mChildren");
mChildren.setAccessible(true);
View[] children = (View[]) mChildren.get(menuView);
for (View child : children) {
if (child.getId() == menuItemId) {
return child;
}
}
return null;
}
假设使用了 android.support.v7.widget。上面的方法将 return 一个与你的菜单项对应的视图。
View menuItemView = getMenuItemView(scToolbar,R.id.AbErase);
int x = menuItemView.getX();
int y = menuItemView.getY();
你有你的坐标。
编辑
经过更多研究后,我发现不需要反射。
在获取 menuItemView
之前,我们必须等待 Toolbar
完成其布局过程
scToolbar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
scToolbar.getViewTreeObserver().removeOnGlobalLayoutListener(this);
View menuItem = findViewById(R.id.AbErase);
if (menuItem != null) {
int[] location = new int[2];
menuItem.getLocationOnScreen(location);
int x = location[0]; //x coordinate
int y = location[1]; //y coordinate
}
}
});
上面的代码片段经测试可以工作,它可以放在任何方便的生命周期回调方法中。
编辑
在查看 activity 的源代码时,必须记住的关键是 View menuItem = findViewById(R.id.AbErase);
只能从 ViewTreeObserver.OnGlobalLayoutListener
、onGlobalLayout
回调中调用。