2012-05-01 10 views

答えて

12

私はついにこれに答えました!ちょっとハッキリですが、それほど多くはありません。唯一の欠点は次のとおりです。

  1. これは3.0+ APIを使用しています。真剣にGoogleは、私たちはそれらを使用することができない場合Androidの新しいバージョンをリリースするのは何ですか? /暴言。
  2. MenuItemを自分のViewに置き換える必要があります。 ImageViewは標準的なものとかなり似ていますが、ツールチップや他のものを見るために長時間押すような機能は欠けています。
  3. 私はそれをたくさんテストしていません。

[OK]を次に示します。

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

そして、あなたはあなたの役に立つ命令はボタンの位置を表示し、それを再描画更新機能を持っている:このような何かにあなたの ActivityonCreateOptionsMenu()を変更

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

は、最後にあなたを作りますボタンの近くに矢印を描く派手なシャーマンのカスタムビュー。 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); 
} 

(ただし、ターゲット位置をキャンバスサイズにクリップする必要があります) Googleと同じ方法を使用して、画面全体にビューをオーバーレイする場合は、そのことについて心配する必要はありませんが、より侵入的です。 Googleの方法ではプライベートAPIは使用していません(驚くほど)。 Launcher2コードでCling.javaをチェックしてください。

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

これは人々に役立つことを願っています!

+0

これは実際に問題なく動作します。私は既にそれが役に立っている時間がすでにありましたが(私はすでに自分のソリューションを使用していました、下記を参照)、アプリケーションを変更することは今の選択肢ではありません。しかし、将来的に他の人に役立つことを願っています!素晴らしい答え! – Pieter888

+0

addOnLayoutChangeListenerはHoneycombからのみサポートされています。それは古いAPIでは動作しません。 –

+0

私は今座標を持っていますが、断片の上に描画する方法は? – Skynet

0

この回答は

上記受け入れ答えを探し、私は(現時点では)メニューアイテムのx/yの値を考え出すの方法がないことが判明、今時代遅れです。ユーザーがメニューボタンを押すまでは、メニュー項目は画面から隠すこともできます。 Android 3.0以降では、アプリのActionBarにメニューを実装するオプションがあります。アクションバーに多くのメニューアイテムを追加することができます。バーにアイテムを配置する場所がなくなると、単にアクションバーに配置できなかったすべてのメニューアイテムを含む「オーバーフロー」ボタンが作成されます。またはプログラマーがオーバーフローメニューに表示するようにメニュー項目を明示的に設定したためです。

このような現象は、おそらくメニュー項目のx/y位置が検索(または設定)できないためです。

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

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

31

私は、アクションバーのボタンにフックをつける別の方法を見つけました。これは、受け入れられた解決策より少し単純かもしれません。 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を使用してプロジェクトでテストされているため、「実際の」アクションバーでは機能しない可能性があります。

+7

リスナーを削除する前に 'if(viewTreeObserver.isAlive())'チェックを追加することを推奨します。なぜならそれが生きていないと例外がスローされることがあるからです。 –

+0

素晴らしい!この素晴らしい答えをありがとう。これは正しいものでなければなりません。 – Cilenco

+0

findViewById - メニュー項目で機能しますか? – Skynet

10

ちょうどこのview..like通常通りにメニュー項目を扱う:

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

注:私は私の活動でテストしてみたがアクションバーとして直接、ツールバーを使用して設定していない...しかし、私同じように動作するはずです。

+0

これをonOptionsItemSelected内で呼び出すこともできます。 – Simon

関連する問題