我想在应用MenuItem
的{{1}}下方显示一个小信息标签。
要正确定位,我需要知道ActionBar
的x位置。
甚至可能吗?
答案 0 :(得分:34)
我找到了另一种在操作栏按钮上获取挂钩的方法,这可能比接受的解决方案简单一些。
您只需使用菜单项的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的项目上测试的,因此它可能不适用于“真正的”操作栏。
答案 1 :(得分:13)
我终于找到了答案!这有点hacky,但不是太多。唯一的缺点是:
MenuItem
替换为您自己的View
。 ImageView
与标准版非常相似,但它缺少长按以查看工具提示等功能,可能还有其他功能。好的,我们就是这样做的。将Activity
的{{1}}更改为以下内容:
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
函数将屏幕坐标转换回Canvas
坐标。像这样:
getLocationOnScreen
(但显然你必须将目标位置剪切为Canvas大小)。如果你采用与谷歌相同的方法,你可以在整个屏幕上覆盖一个视图,你不必担心这一点,但它更具侵入性。 Google的方法肯定不会使用任何私有API(令人惊讶)。查看Launcher2代码中的@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.java
),您会发现它更加黑客。它们基本上使用由使用哪种布局确定的绝对屏幕位置。
希望这有助于人们!
答案 2 :(得分:11)
只需将菜单项作为普通视图处理。就像这样:
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配置了我的活动测试,而不是直接作为ActionBar ...但我猜它应该有相似的功能。
答案 3 :(得分:0)
此答案现已过时,请查看上面接受的答案
我发现(此时)无法确定菜单项的x / y值。在用户按下菜单按钮之前,看到菜单项也可以隐藏在屏幕上。在Android 3.0及更高版本中,您可以选择在应用的ActionBar
中实现菜单。您可以在操作栏中添加许多菜单项,当没有更多位置在栏上放置项目时,它只会创建一个“溢出”按钮,其中包含无法放置在操作栏上的所有菜单项,因为空间不足或程序员明确设置菜单项出现在溢出菜单中。
所有这些行为都可能是菜单项没有你可以检索(或设置)的x / y位置的原因。
我最终如何解决这个问题是通过使用Paint.measureText()
函数来确定每个菜单项在操作栏中应该有多宽,并使用它来计算屏幕右侧的偏移量标签应该是。
这是一种解决方法,但如果有人遇到与我相同的问题,请知道这很好用。只需记住在Paint
对象上设置合适的字体大小,否则当您测量文本的长度时,它很可能使用与菜单项的字体大小不同的字体大小来计算文本宽度。