片段未接收菜单回调

时间:2011-06-08 13:37:06

标签: android android-fragments fragment

我有一个扩展Fragment的片段类,并调用setHasOptionsMenu参与菜单。此类还实现了onCreateOptionsMenuonPrepareOptionsMenuonOptionsItemSelected

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

我在我的Activity(扩展FragmentTransaction)中使用FragmentActivity动态加载此片段。

但是没有调用任何菜单回调(onCreateOptionsMenuonPrepareOptionsMenuonOptionsItemSelected)(我在这些方法中调试了一些断点)并且菜单未显示

我错过了什么吗?我需要在我的活动中添加一些内容吗?

我正在使用Android兼容性库,使用L11 SDK进行编译并在Xoom中进行测试。

编辑:我发现了问题。我的AndroidManifest目标是L11,这似乎隐藏了菜单按钮并阻止了回调被调用。但是,如果我从清单中删除它,我会丢失一些我需要的其他功能(例如列表中的激活状态)。有没有人知道如何解决这个问题(启用菜单按钮)而不从清单中删除targetSdkVersion=11

12 个答案:

答案 0 :(得分:29)

Aromero, 不要忘记使用方法的片段版本覆盖onCreateOptionsMenu,类似于:

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

顺便说一句,这会在片段中进行,并添加到Activity的膨胀菜单中(如果有的话)。我自己也有同样的问题,直到我想出来。

答案 1 :(得分:9)

如果你在ActionBarSherlock中遇到这个问题,你需要确保你的片段是SherlockFragments,而不仅仅是支持片段,而你要覆盖的是

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

不是

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

如果你做了后者,你应该得到关于函数是final的警告,你无法覆盖它。这是一个警告,你试图覆盖错误的功能!

如果通过将类从SherlockFragment切换到仅仅片段来修复错误,则可以创建该函数。 。 。但它不会被调用。

答案 2 :(得分:9)

我遇到了同样的问题,但我认为最好总结一下并介绍最后一步让它发挥作用:

  1. 在Fragment的onCreate(Bundle savedInstanceState)方法中添加setHasOptionsMenu(true)方法。

  2. 在片段中覆盖onCreateOptionsMenu(Menu menu, MenuInflater inflater)(如果您想在片段菜单中执行不同的操作)和onOptionsItemSelected(MenuItem item)方法。

  3. onOptionsItemSelected(MenuItem item) Activity的方法中,确保在onOptionsItemSelected(MenuItem item) Fragment方法中实现菜单项操作时返回false。

  4. 一个例子:

    活动

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

    我希望这会有所帮助。

    干杯。

答案 3 :(得分:6)

如果你有一个活动和一个片段,每个片段都加载菜单项,那么你需要特别注意你使用的覆盖。

活动可以覆盖 onOptionsItemSelected onMenuItemSelected ,但片段只能覆盖 onOptionsItemSelected

如果您在活动中覆盖 onMenuItemSelected 并在片段中覆盖 onOptionsItemSelected ,则您的片段覆盖将永远不会被触发。

相反,在activity和fragment中使用 onOptionsItemSelected

答案 4 :(得分:5)

您需要确保在片段中调用setHasOptionsMenu(true); onCreateonCreateView

您还需要在片段中实现onCreateOptionsMenu的覆盖。

答案 5 :(得分:4)

另一种可能的情况是,在每个片段中使用公共ID进行公共操作时;例如R.id.action_add

今天我遇到了这种情况:点击选项菜单[add]被调用“错误”onOptionItemSelected因为每个片段(使用DrawerLayout动态替换)具有相同的R.id.action_add

简短的故事,如果您有这种情况,请始终检查您的片段是否可见:

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())返回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
}

答案 6 :(得分:3)

当我将ViewPagerIndicator与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);

}

答案 7 :(得分:2)

我发现了问题。 AndroidManifest的目标是SDK 11,这似乎隐藏了菜单按钮并阻止调用回调。我认为这打破了菜单按钮的兼容性,似乎被Android 3.0中的操作栏取代了

答案 8 :(得分:1)

我认为您已在onCreateOptionsMenu的班级中实施了onPrepareOptionsMenuonOptionsItemSelectedextends Fragment。尝试在您正在加载此片段的Activity类中执行此操作

答案 9 :(得分:1)

我有同样的问题和解决方案对我有用:

  1. 删除或评论任何onOptionsItemSelected(),onMenuItemSelected()甚至onPrepareOptionMenu()并仅留在Activity 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;
         }
    
  4. 在Android 4.4上测试并使用

答案 10 :(得分:1)

来自Android开发者网站 - link

  

注意:如果您通过片段从片段中膨胀菜单项   class onCreateOptionsMenu()回调,系统调用   当用户选择其中一个时,该片段的onOptionsItemSelected()   那些物品。但是,活动有机会处理该事件   首先,所以 系统首先调用onOptionsItemSelected()   活动,在调用片段的相同回调 之前。确保   活动中的任何片段也有机会处理   回调,始终将调用传递给超类作为默认值   当您不处理该项目时,行为而不是返回 false

因此Marco HC是最好的答案。

答案 11 :(得分:1)

如果您的工具栏是在父活动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);
}

这是唯一对我有用的解决方案!