我想在应用程序的 ActionBar
中的 MenuItem
下方显示一小段信息标签。
为了正确定位这个标签,我需要知道 MenuItem
的x位置。
目前谷歌没有给出有用的结果。
这是否可行?
我想在应用程序的 ActionBar
中的 MenuItem
下方显示一小段信息标签。
为了正确定位这个标签,我需要知道 MenuItem
的x位置。
目前谷歌没有给出有用的结果。
这是否可行?
我发现另一种获取操作栏按钮钩子的方法,可能比已接受的解决方案更简单。您可以使用菜单项的ID简单地调用findViewById
!
现在难点是何时调用此功能?在onCreate
和onResume
中,这太早了。一种解决方法是使用窗口的ViewTreeObserver
:
final ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
View menuButton = findViewById(R.id.menu_refresh);
// This could be called when the button is not there yet, so we must test for null
if (menuButton != null) {
// Found it! Do what you need with the button
int[] location = new int[2];
menuButton.getLocationInWindow(location);
Log.d(TAG, "x=" + location[0] + " y=" + location[1]);
// Now you can get rid of this listener
viewTreeObserver.removeGlobalOnLayoutListener(this);
}
}
});
这个代码应该放在 onCreate
方法里。
注意:这是在使用 ActionBarSherlock 的项目上测试过的,所以在一个“真正”的 action bar 上可能无法工作。
你需要用自己的 View
替换 MenuItem
。虽然一个 ImageView
和标准的 ImageView 很相似,但它缺少长按查看工具提示等功能,可能还有其他。
我没有进行大量测试。
好的,下面是具体实现方法。将你的 Activity
的 onCreateOptionsMenu()
更改为以下内容:
View mAddListingButton;
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
// Find the menu item we are interested in.
MenuItem it = menu.findItem(R.id.item_new_listing);
// Create a new view to replace the standard one.
// It would be nice if we could just *get* the standard one
// but unfortunately it.getActionView() returns null.
// actionButtonStyle makes the 'pressed' state work.
ImageView button = new ImageView(this, null, android.R.attr.actionButtonStyle);
button.setImageResource(R.drawable.ic_action_add_listing);
// The onClick attributes in the menu resource no longer work (I assume since
// we passed null as the attribute list when creating this button.
button.setOnClickListener(this);
// Ok, now listen for when layouting is finished and the button is in position.
button.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom)
{
// Apparently this can be called before layout is finished, so ignore it.
// Remember also that it might never be called with sane values, for example
// if your action button is pushed into the "more" menu thing.
if (left == 0 && top == 0 && right == 0 && bottom == 0)
return;
// This is the only way to get the absolute position on the screen.
// The parameters passed to this function are relative to the containing View
// and v.getX/Y() return 0.
int[] location = new int[2];
v.getLocationOnScreen(location);
// Ok, now we know the centre location of the button in screen coordinates!
informButtonLocation(location[0] + (right-left)/2, location[1] + (bottom-top)/2);
}
});
it.setActionView(button);
mAddListingButton = it.getActionView();
return true;
}
private void informButtonLocation(int cx, int cy)
{
MyHelpView v = (MyHelpView)findViewById(R.id.instructions);
v.setText("Click this button.");
v.setTarget(cx, cy);
}
最后,制作一个花哨的自定义视图,向(接近)按钮绘制箭头。在onDraw
方法中,您可以使用相同的getLocationOnScreen
函数将屏幕坐标转换回Canvas
坐标。代码示例如下:
@Override
public void onDraw(Canvas canvas)
{
int[] location = new int[2];
getLocationOnScreen(location);
canvas.drawColor(Color.WHITE);
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(40);
mPaint.setAntiAlias(true);
mPaint.setTextAlign(Align.CENTER);
canvas.drawText(mText, getWidth()/2, getHeight()/2, mPaint);
// Crappy line that isn't positioned right at all and has no arrowhead.
if (mTargetX != -1 && mTargetY != -1)
canvas.drawLine(getWidth()/2, getHeight()/2,
mTargetX - location[0], mTargetY - location[1], mPaint);
}
顺便说一句,如果您查看Google为启动器实现类似功能的源代码(他们称说明屏幕为“Cling”,原因不详),则可以看到它甚至更加令人费解。基本上,他们使用由使用哪个布局确定的绝对屏幕位置。
希望这能帮助人们!
将菜单项视为普通视图进行处理,就像这样:
View myActionView = findViewById(R.id.my_menu_item_id);
if (myActionView != null) {
int[] location = new int[2];
myActionView.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
Log.d(TAG, "menu item location --> " + x + "," + y);
}
注意:我已经测试了使用ToolBar配置的Activity,而不是直接使用ActionBar...但我想它应该工作得相似。
此答案已过时,请查看上面的被采纳的答案
我发现(目前)无法确定菜单项的x/y值。请注意,菜单项可能会在用户按下菜单按钮之前隐藏在屏幕上。在Android 3.0及以上版本中,您可以选择在应用程序的ActionBar
中实现菜单。您可以在操作栏中添加许多菜单项,当操作栏上没有足够的空间放置一个项目时,它将简单地创建一个“溢出”按钮,其中包含所有不能放置在操作栏上的菜单项,因为空间不足或程序员明确设置了菜单项出现在溢出菜单中。
所有这些行为可能就是为什么菜单项没有它们的x/y位置可以检索(或设置)的原因。
我最终是通过使用Paint.measureText()
函数来确定每个菜单项在操作栏中的宽度,并将其用于计算标签应该位于屏幕右侧的偏移量来解决这个问题。
这是一个解决方法,但如果有人遇到和我一样的问题,请知道这个方法可以正常工作。只需记得在Paint
对象上设置适当的字体大小,否则当您测量文本长度时,它很可能会使用与菜单项字体大小不同的字体大小计算文本宽度。
if(viewTreeObserver.isAlive())
检查,因为如果它不再活动,有时会抛出异常。 - M.Sameer