web-dev-qa-db-ja.com

フラグメントがメニューコールバックを受信しない

Fragmentを拡張し、setHasOptionsMenuを呼び出してメニューに参加するフラグメントクラスがあります。このクラスは、onCreateOptionsMenuonPrepareOptionsMenu、およびonOptionsItemSelectedも実装します。

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        ....
}

私のアクティビティでFragmentTransactionを使用してこのフラグメントを動的にロードしています(FragmentActivityを拡張しています)。

ただし、メニューコールバック(onCreateOptionsMenuonPrepareOptionsMenuおよびonOptionsItemSelected)のいずれも呼び出されず(これらのメソッドにいくつかのブレークポイントを設定してデバッグしました)、メニューは表示されません。 。

何か不足していますか?アクティビティに何かを追加する必要がありますか?

Android互換性ライブラリを使用して、L11 SDKでコンパイルし、Xoomでテストしています。

[〜#〜] edit [〜#〜]:問題が見つかりました。私のAndroidManifestはL11をターゲットにしています。これによりメニューボタンが非表示になり、コールバックが呼び出されないように見えます。しかし、これをマニフェストから削除すると、必要な他の機能がいくつか失われます(たとえば、リストのアクティブ化された状態)。マニフェストからtargetSdkVersion=11を削除せずにこの問題を解決する方法(メニューボタンを有効にする)を知っている人はいますか?

40
aromero

問題を見つけました。 AndroidManifestはSDK 11をターゲットにしているため、メニューボタンが非表示になり、コールバックが呼び出されないようになっています。これにより、Android 3.0でアクションバーに置き換えられたように見えるメニューボタンの互換性が損なわれると思います

2
aromero

Aromero、次のように、メソッドのフラグメントバージョンを使用してonCreateOptionsMenuをオーバーライドすることを忘れないでください。

    @Override
    public void onCreateOptionsMenu (Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.queue_options, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

ちなみに、これはフラグメントに含まれ、アクティビティがある場合は、そのメニューに追加されます。私がこれを理解するまで、私自身も同じ問題を抱えていました。

キム

29
user553456

私は同じ問題を抱えていましたが、それを機能させるための最後のステップを要約して紹介する方が良いと思います:

  1. フラグメントのonCreate(Bundle savedInstanceState)メソッドにsetHasOptionsMenu(true)メソッドを追加します。

  2. onCreateOptionsMenu(Menu menu, MenuInflater inflater)(Fragmentのメニューで別のことを実行したい場合)およびFragmentのonOptionsItemSelected(MenuItem item)メソッドをオーバーライドします。

  3. onOptionsItemSelected(MenuItem item)アクティビティのメソッド内で、メニュー項目アクションがonOptionsItemSelected(MenuItem item)フラグメントのメソッドに実装される場合は、必ずfalseを返します。

例:

アクティビティ

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.activity_menu_item:
        // Do Activity menu item stuff here
        return true;
    case R.id.fragment_menu_item:
        // Not implemented here
        return false;
    default:
        break;
    }

    return false;
}

フラグメント

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    ....
}

@Override
public void onCreateOptionsMenu(Menu menu) {
    // Do something that differs the Activity's menu here
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.activity_menu_item:
        // Not implemented here
        return false;
    case R.id.fragment_menu_item:
        // Do Fragment menu item stuff here
        return true;
    default:
        break;
    }

    return false;
}

これがお役に立てば幸いです。

乾杯。

9
Marco HC

ActionBarSherlockでこの問題が発生している場合は、フラグメントが単なるSupportFragmentsではなくSherlockFragmentsであること、およびオーバーライドしているものが

public void onPrepareOptionsMenu (com.actionbarsherlock.view.Menu menu) {

ない

public void onPrepareOptionsMenu (Android.view.Menu menu) {

後者を実行すると、関数が最終的であり、それをオーバーライドできないことについて、何らかの警告が表示されます。これは、間違った関数をオーバーライドしようとしているという警告です!

クラスをSherlockFragmentから単なるFragmentに切り替えることでエラーを修正すると、関数を作成できます。 。 。呼び出されません。

9

それぞれがメニュー項目をロードするアクティビティとフラグメントがある場合は、使用するオーバーライドに特別な注意を払う必要があります。

アクティビティはonOptionsItemSelectedおよびonMenuItemSelectedをオーバーライドできますが、フラグメントはonOptionsItemSelectedのみをオーバーライドできます。

アクティビティでonMenuItemSelectedをオーバーライドし、フラグメントでonOptionsItemSelectedをオーバーライドした場合、フラグメントオーバーライドはトリガーされません。

代わりに、アクティビティとフラグメントの両方でonOptionsItemSelectedを使用します。

6
Error 454

フラグメントでsetHasOptionsMenu(true);onCreateまたはonCreateViewが呼び出されていることを確認する必要があります。

また、フラグメント内にonCreateOptionsMenuのオーバーライドを実装する必要があります。

5
Nelson Ramirez

別の可能なケースは、各フラグメントの共通アクションに共通IDを使用する場合です。たとえばR.id.action_add

今日、私はそのような状況にありました。各フラグメント(onOptionItemSelectedを使用して動的に置き換えられた)が同じ_R.id.action_add_を持っていたため、オプションメニュー[追加]を押すと「間違った」DrawerLayoutが呼び出されました。

短い話ですが、そのような状況にある場合は、フラグメントが表示されていることを常に確認してください。

if (!isVisible()) return false;

長い話ですが、onOptionItemSelectedチェーンに注目してください!

_  MainActivity
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment1
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment2
       |
       |  onOptionItemSelected
       +-----------------------
       |     return true
       |
[item selection handled]
_

あなたがあなたのフラグメントを(何かのような)これを追加すると:

_getSupportFragmentManager()
   .beginTransaction()
   .replace(R.id.content_frame, MyCoolFragment1.newInstance())
   .commit() 
_

そして、各フラグメントの共通アクション(たとえば、R.id.action_add)に同じIDを定義しました。それぞれにこの行を追加することを忘れないでください:if(!isVisible())return false;

_@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (!isVisible()) return false; // <-- Not visible? skip!

    if (item.getItemId() == R.id.action_add) {
        //.TODO whatever
        return true;  //.Handled!
    }

    return false; //.Skip
}
_
4
Luca Sepe

ViewBarrIndicatorをActionBarSherlockと組み合わせて使用​​していたときに、この問題が発生しました。これは fixed のようでしたが、まだ問題が発生しました。私が見つけた回避策は、フラグメントを手動で呼び出すことでした。

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    Toast.makeText(this, "From activity", Toast.LENGTH_SHORT).show(); // TODO
    Fragment currentFragment = mAdapter.getItem(mPager.getCurrentItem());
    if (currentFragment != null && currentFragment instanceof SherlockFragment)
    {
        ((SherlockFragment)currentFragment).onOptionsItemSelected(item);
    }
    return super.onOptionsItemSelected(item);

}
3
AlexUT

ツールバーが親アクティビティxmlで定義されている場合は、フラグメントでこれを実行してください。

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    ....
    Toolbar toolbar = (Toolbar)getActivity().findViewById(R.id.toolbar);
    ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
    setHasOptionsMenu(true);
}

そしてもちろん、以下のようにonCreateOptionsMenuをオーバーライドします

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.edit_menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

これは私のために働いた唯一の解決策です!

1
reavcn

Android開発者サイト- link から

注:FragmentクラスのonCreateOptionsMenu()コールバックを介してフラグメントからメニュー項目をインフレートする場合、ユーザーがそれらの項目の1つを選択すると、システムはそのフラグメントのonOptionsItemSelected()を呼び出します。ただし、アクティビティは最初にイベントを処理する機会があるため、フラグメントの同じコールバックを呼び出す前に、システムはまずアクティビティのonOptionsItemSelected()を呼び出します。アクティビティ内のフラグメントにもコールバックを処理する機会があることを確認するには、falseを返すのではなく、常にデフォルトの動作としてスーパークラスに呼び出しを渡します取り扱っていない場合.

したがって、 Marco HC が最も良い答えです。

1
ik024

onCreateOptionsMenuonPrepareOptionsMenuonOptionsItemSelectedextends Fragment。このフラグメントをロードしているActivityクラスでそれをやってみてください

1

私は同じ問題を抱えていて、私のために働いた解決策は次のとおりです:

  1. OnPrepareOptionMenu()であってもonOptionsItemSelected()、onMenuItemSelected()を削除またはコメント化して、アクティビティのonCreateOptionsMenu()のみに残します。

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
    MenuInflater inflater=getMenuInflater();
    inflater.inflate(R.layout.menu, menu);
    return true;
    }
    
  2. FragmentクラスのonCreateView()に次のように記述します。

    setHasOptionsMenu(true);
    
  3. Fragmentクラスに次を追加します。

    @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
     super.onCreateOptionsMenu(menu,inflater);      
     }
    
    @Override
     public boolean onOptionsItemSelected(MenuItem item){           
             switch(item.getItemId()){
             case R.id.action_insert:
                //doing stuff
             return true;
             }
             return false;
         }
    

テスト済みで動作Android 4.4

1