我怎样才能得到一个动作条菜单项的当前位置?当前位置、菜单项、动作

2023-09-05 05:36:21 作者:少年心事当浮云

我要显示一个菜单项下面一点点信息标签在应用程序的动作条。 要正确定位这一点,我需要知道的x位置菜单项

I want to show a little info label underneath a MenuItem in the app's ActionBar. To position this correctly I need to know the x-position of a MenuItem.

谷歌给我带来任何有用的结果为止。

Google brought me no useful results so far.

它甚至有可能吗?

推荐答案

我终于找到一个答案!这是一个有点哈克,但不会太大。唯一的缺点是:

I finally found an answer to this! It is a bit hacky, but not too much. The only downsides are:

它使用一个3.0+ API。认真不过谷歌,如果释放的Andr​​oid的新版本,如果我们不能使用它们的点? /咆哮。 您必须用自己的查看替换菜单项秒。一个的ImageView 是相当类似的标准之一,但它忽略像长pressing功能看到工具提示,也许其他的东西。 在我还没有测试它了。 It uses a 3.0+ API. Seriously though Google, what's the point of releasing new versions of Android if we can't use them? /rant. You have to replace the MenuItems with your own View. An ImageView is fairly similar to the standard one but it misses features like long-pressing to see a tool-tip, and probably other things. I haven't tested it a lot.

好吧,这里是我们如何做到这一点。改变你的活动 onCreateOptionsMenu()来是这样的:

Ok, here's how we do it. Change your Activity's onCreateOptionsMenu() to something like this:

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

然后你有一个功能,更新您有帮助的说明,请查看与按钮的位置,并重绘:

And then you have a function that updates your helpful instructions view with the location of the button and redraws it:

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

最后做出绘制一个箭头(近)的按钮,你看中的schmancy自定义视图。在你的的OnDraw 方法,我们也可以将屏幕坐标回画布坐标使用相同的 getLocationOnScreen将功能。事情是这样的:

Finally make your fancy schmancy custom view that draws an arrow to (near) the button. In your onDraw method you can convert the screen coordinates back to Canvas coordinates using the same getLocationOnScreen function. Something like this:

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

(但显然你必须夹的目标位置画布大小)。如果你去了,你覆盖以期在整个屏幕上,你将不必担心同样的方法,谷歌,但它是更具侵入性。谷歌的方法,绝对不使用任何私有的API(惊人的)。看看 Cling.java 中的launcher2 code。

(But obviously you have to clip the target location to the Canvas size). If you go for the same method as Google where you overlay a view over the entire screen you won't have to worry about that, but it is more intrusive. Google's method definitely doesn't use any private APIs (amazingly). Check out Cling.java in the Launcher2 code.

顺便说一句,如果你看看源为发射谷歌的类似执行本(他们称之为的说明筛选保鲜出于某种原因),你可以看到,它更是哈克。他们基本上是使用由该布局被用来确定绝对的屏幕位置。

Incidentally, if you look at the source for Google's similar implementation of this for the launcher (they call the instructions screen a Cling for some reason), you can see that it is even more hacky. They basically use absolute screen positions determined by which layout is being used.

希望这有助于人!