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

Pie*_*888 20 android android-layout

我想MenuItem在应用程序的下方显示一个小信息标签ActionBar.要正确定位,我需要知道a的x位置MenuItem.

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

它甚至可能吗?

BoD*_*BoD 34

我找到了另一种方法来获取操作栏按钮上的钩子,这可能比接受的解决方案稍微简单一些.您只需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);
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

这进入了onCreate.

注意:这是在使用ActionBarSherlock的项目上测试的,因此它可能无法与"真实"操作栏一起使用.

  • 我建议在删除监听器之前添加`if(viewTreeObserver.isAlive())`check,因为如果它不活动,有时会抛出异常. (7认同)

Tim*_*mmm 13

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

  1. 它使用3.0+ API.严重的是谷歌,如果我们不能使用它们,发布新版Android的重点是什么?/咆哮.
  2. 你必须MenuItem用自己的替换s View.An ImageView与标准版非常相似,但它缺少长按以查看工具提示等功能,以及其他可能的功能.
  3. 我没有测试过很多.

好的,这就是我们如何做到的.把你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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

最后制作你的花式施法自定义视图,将箭头绘制到(靠近)按钮.在您的onDraw方法中,您可以Canvas使用相同的getLocationOnScreen功能将屏幕坐标转换回坐标.像这样的东西:

@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);
}
Run Code Online (Sandbox Code Playgroud)

(但显然你必须将目标位置剪切到Canvas大小).如果你采用与谷歌相同的方法,你可以在整个屏幕上覆盖一个视图,你不必担心这一点,但它更具侵入性.Google的方法肯定不会使用任何私有API(令人惊讶).查看Cling.javaLauncher2代码.

顺便提一下,如果你看一下Google为启动器执行此类操作的相似内容(他们Cling出于某种原因将其称为指令屏幕),你会发现它更加黑客.它们基本上使用由使用哪种布局确定的绝对屏幕位置.

希望这有助于人们!


Alé*_*lho 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);
    }
Run Code Online (Sandbox Code Playgroud)

注意: 我已经使用ToolBar配置了我的活动测试,而不是直接作为ActionBar进行测试...但我想它应该可以正常工作.