21

MenuItemアプリの の下に小さな情報ラベルを表示したいと思いActionBarます。これを正しく配置するには、 a の x 位置を知る必要がありMenuItemます。

これまでのところ、Google は有用な結果をもたらしませんでした。

それは可能ですか?

4

4 に答える 4

34

アクションバーボタンにフックを付ける別の方法を見つけました。これは、受け入れられている解決策よりも少し簡単かもしれません。findViewByIdメニュー項目の id を使用して を呼び出すだけです。

ここで難しいのは、いつこれを呼び出すことができるかということです。onCreateとではonResume、早すぎます。これを行う 1 つの方法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 を使用するプロジェクトでテストされているため、「実際の」アクション バーでは機能しない可能性があります。

于 2012-11-09T00:14:26.740 に答える
14

私はついにこれに対する答えを見つけました!少しハッキーですが、それほど多くはありません。唯一の欠点は次のとおりです。

  1. MenuItems を独自のに置き換える必要がありますView。は標準のImageViewものとかなり似ていますが、長押ししてツールチップを表示するなどの機能が欠けています。

  2. 私はそれをあまりテストしていません。

わかりました、これが私たちのやり方です。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;
}

次に、ボタンの位置を使用して役立つ指示ビューを更新し、再描画する関数があります。

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

最後に、ボタンの (近くに) 矢印を描画する派手なカスタム ビューを作成します。メソッドでは、同じ関数を使用onDrawして画面座標を座標に戻すことができます。このようなもの:CanvasgetLocationOnScreen

@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 と同じ方法を使用する場合は、心配する必要はありませんが、より煩わしくなります。Google の方法は、(驚くべきことに) プライベート API をまったく使用していません。Cling.javaLauncher2 コードをチェックアウトします。

ちなみに、これをランチャーに実装した Google の同様の実装 (Cling何らかの理由で指示画面を a と呼んでいます) のソースを見ると、さらにハックであることがわかります。基本的に、どのレイアウトが使用されているかによって決定される絶対画面位置を使用します。

これが人々を助けることを願っています!

于 2012-07-15T19:20:02.760 に答える
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);
    }

注: ActionBar として直接ではなく、ToolBar を使用して構成されたアクティビティでテストしましたが、同様に動作するはずです。

于 2015-05-13T13:49:58.683 に答える
0

この回答は現在古くなっています。上記の受け入れられた回答を探してください

(現時点では) メニュー項目の x/y 値を計算する方法がないことがわかりました。メニュー項目は、ユーザーがメニュー ボタンを押すまで画面から非表示にすることもできます。Android 3.0 以降では、アプリの にメニューを実装するオプションがありますActionBar。アクションバーに多くのメニューアイテムを追加できます。バーにアイテムを配置する場所がなくなった場合、アクションバーに配置できなかったすべてのメニューアイテムを含む「オーバーフロー」ボタンが作成されます。スペースが不足している、またはプログラマーが明示的にメニュー項目をオーバーフロー メニューに表示するように設定したためです。

このすべての動作が、メニュー項目に取得 (または設定) できる x/y 位置がない理由であると考えられます。

この問題を最終的にどのように解決したかは、Paint.measureText()関数を使用してアクション バー内の各メニュー項目の幅を決定し、それを使用して、ラベルがあるべき画面の右側からのオフセットを計算することです。

これは回避策ですが、誰かが私と同じ問題を抱えている場合は、これでうまくいくことを知っておいてください。オブジェクトに適切な font-size を設定することを忘れないでPaintください。 そうしないと、テキストの長さを測定するときに、メニュー項目の font-size とは異なる font-size を使用してテキストの幅が計算される可能性が高くなります。

于 2012-05-16T12:26:15.247 に答える