如何获取ActionBar MenuItem的当前位置?

时间:2012-05-01 12:27:05

标签: android android-layout

我想在应用MenuItem的{​​{1}}下方显示一个小信息标签。 要正确定位,我需要知道ActionBar的x位置。

到目前为止,谷歌没有给我带来任何有用的结果。

甚至可能吗?

4 个答案:

答案 0 :(得分:34)

我找到了另一种在操作栏按钮上获取挂钩的方法,这可能比接受的解决方案简单一些。 您只需使用菜单项的ID调用findViewById即可!

现在困难的部分是 你能打电话吗?在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的项目上测试的,因此它可能不适用于“真正的”操作栏。

答案 1 :(得分:13)

我终于找到了答案!这有点hacky,但不是太多。唯一的缺点是:

  1. 它使用3.0+ API。严重的是谷歌,如果我们不能使用它们,发布新版Android的重点是什么? /咆哮。
  2. 您必须将MenuItem替换为您自己的ViewImageView与标准版非常相似,但它缺少长按以查看工具提示等功能,可能还有其他功能。
  3. 我没有对它进行过多次测试。
  4. 好的,我们就是这样做的。将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对象上设置合适的字体大小,否则当您测量文本的长度时,它很可能使用与菜单项的字体大小不同的字体大小来计算文本宽度。