我如何获得ActionBar MenuItem的当前位置?

我想在应用程序的ActionBarMenuItem下面显示一个小信息标签。 为了正确定位,我需要知道MenuItem的x位置。

到目前为止Google没有给我带来有用的结果。

这甚至有可能吗?

Solutions Collecting From Web of "我如何获得ActionBar MenuItem的当前位置?"

我终于find了答案! 这有点哈克,但不是太多。 唯一的缺点是:

  1. 它使用3.0+ API。 认真地说,谷歌,如果我们不能使用它们,发布新版本的Android有什么意义? /咆哮。
  2. 你必须用你自己的View来代替MenuItem 。 一个ImageView与标准的ImageView非常相似,但是却没有像长按一样看到一个工具提示,还有其他的东西。
  3. 我还没有testing过很多。

好的,我们是这样做的。 改变你的ActivityonCreateOptionsMenu()如下所示:

 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; } 

然后你有一个函数,用button的位置更新你有用的指令视图,并重画它:

 private void informButtonLocation(int cx, int cy) { MyHelpView v = (MyHelpView)findViewById(R.id.instructions); v.setText("Click this button."); v.setTarget(cx, cy); } 

最后使你的花式schmancy自定义视图,绘制一个箭头(靠近)button。 在您的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); } 

(但显然你必须剪辑目标位置的canvas大小)。 如果您采用与Google相同的方法,您可以在整个屏幕上覆盖一个视图,则不必担心这个问题,但这样做更具侵扰性。 Google的方法绝对不会使用任何私有API(令人惊讶的)。 在Launcher2代码中查看Cling.java

顺便说一句,如果你看看谷歌类似的执行这个启动器的来源(他们称之为屏幕Cling出于某种原因),你可以看到它更加黑客。 他们基本上使用绝对的屏幕位置决定使用哪个布局。

希望这有助于人们!

我发现另一种方法来获得一个操作栏button的钩子,这可能比接受的解决scheme稍微简单一些。 您可以简单地调用findViewById ,与菜单项的ID!

现在最困难的部分是你什么时候可以打电话? 在onCreateonResume ,现在还为时过早。 那么一个方法是使用窗口的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的项目上testing的,所以它可能不适用于“真正的”操作栏。

只要处理菜单项作为一个普通的看法..就像这样:

  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); } 

注意: 我已经使用ToolBarconfiguration了我的活动,而不是直接作为ActionBar …但是我想它应该以类似的方式工作。

这个答案现在已经过时了,请看上面的答案

我发现(在这个时候)没有办法计算菜单项的x / y值。 看到菜单项可以隐藏在屏幕上,直到用户按下菜单button。 在Android 3.0及更高版本中,您可以select在应用程序的ActionBar实现菜单。 您可以在操作栏中添加很多菜单项,当没有更多的位置来放置一个项目时,它只会创build一个“溢出”button,其中将包含所有无法放置在操作栏上的菜单项,因为的空间不足或者程序员明确地设置菜单项出现在溢出菜单中。

所有这些行为可能是为什么菜单项没有你可以检索(或设置)的x / y位置。

我最终如何解决这个问题是通过使用Paint.measureText()函数来确定每个菜单项在操作栏应该有多宽,并使用它来计算从标签应该在屏幕右侧的偏移量。

这是一个解决方法,但如果有人遇到与我一样的问题,请确认这个工作正常。 只要记住在Paint对象上设置适当的字体大小,否则当你测量文本的长度时,它将很可能使用与菜单项的字体大小不同的字体大小来计算文本宽度。