上下文菜单不适用于两个片段

Posted

技术标签:

【中文标题】上下文菜单不适用于两个片段【英文标题】:context menu not working with two fragments 【发布时间】:2014-12-30 13:15:30 【问题描述】:

我有两个片段 A 和 B,它们都有一个列表视图,并从基本片段 C 扩展。实际上 A 和 B 从 C 扩展了列表视图控件。

为了实现长按功能,我在 C 中注册了上下文菜单。

现在当我长按片段 A 或 B 时,上下文菜单可以按预期显示。此外,当我在片段 A 中时,上下文菜单也可以正常工作。

但我们导航到片段 B,长按列表,onContextItemSelected 方法从未被调用。

我是这样做的。 首先,在 Fragment C 的onActivityCreated 中注册上下文菜单。

registerForContextMenu(transferTasksList);

其次,在 Fragment C 中设置布局并绘制菜单。

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
                                ContextMenu.ContextMenuInfo menuInfo) 
    super.onCreateContextMenu(menu, v, menuInfo);
    android.view.MenuInflater inflater = mActivity.getMenuInflater();
    inflater.inflate(R.menu.upload_task_menu, menu);

    ListView listView = (ListView)v;
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
    TransferTaskInfo taskInfo = (TransferTaskInfo)listView.getItemAtPosition(info.position);

    android.view.MenuItem itemCancel = menu.findItem(R.id.cancel);
    android.view.MenuItem itemRetry = menu.findItem(R.id.retry);
    android.view.MenuItem itemRemove = menu.findItem(R.id.remove);
    android.view.MenuItem itemRemoveAllCancelled = menu.findItem(R.id.remove_all_cancelled);
    android.view.MenuItem itemRemoveAllFinished = menu.findItem(R.id.remove_all_finished);

    itemCancel.setVisible(false);
    itemRetry.setVisible(false);
    itemRemove.setVisible(false);
    itemRemoveAllCancelled.setVisible(false);
    itemRemoveAllFinished.setVisible(false);

    switch (taskInfo.state) 
        case INIT:
            itemCancel.setVisible(true);
            break;
        case TRANSFERRING:
            itemCancel.setVisible(true);
            break;
        case CANCELLED:
            itemRetry.setVisible(true);
            itemRemove.setVisible(true);
            itemRemoveAllCancelled.setVisible(true);
            break;
        case FAILED:
            itemRetry.setVisible(true);
            itemRemove.setVisible(true);
            break;
        case FINISHED:
            itemRemove.setVisible(true);
            itemRemoveAllFinished.setVisible(true);
            break;
    

三、通过Fragment C中的抽象方法doContextItemSelected捕捉点击事件。

@Override
    public boolean onContextItemSelected(android.view.MenuItem item) 
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();

        TransferService txService = mActivity.getTransferService();

        if (txService == null) 
            return false;
        

        ListView listView = transferTasksList;
        TransferTaskInfo taskInfo = (TransferTaskInfo)listView.getItemAtPosition(info.position);
        TransferManager.TaskState state = taskInfo.state;
        int taskID = taskInfo.taskID;

        boolean needRefresh = doContextItemSelected(item, taskID, state);

        if (needRefresh) 
            refreshView();
        
        return true;
    

而我实现的抽象方法是这样的A和B。

@Override
boolean doContextItemSelected(MenuItem item, int taskID, TransferManager.TaskState state) 
    switch (item.getItemId()) 
        case R.id.cancel:
            if (state == TransferManager.TaskState.INIT || state == TransferManager.TaskState.TRANSFERRING) 
                mActivity.getTransferService().cancelUploadTask(taskID);
                return true;
            
            break;
        case R.id.retry:
            if (state == TransferManager.TaskState.FAILED || state == TransferManager.TaskState.CANCELLED) 
                mActivity.getTransferService().retryUploadTask(taskID);
                return true;
            
            break;
        case R.id.remove:
            if (state == TransferManager.TaskState.FINISHED ||
                    state == TransferManager.TaskState.FAILED ||
                    state == TransferManager.TaskState.CANCELLED) 
                mActivity.getTransferService().removeUploadTask(taskID);
                return true;
            
            break;
        case R.id.remove_all_cancelled:
            if (state == TransferManager.TaskState.CANCELLED) 
                mActivity.getTransferService().removeAllUploadTasksByState(TransferManager.TaskState.CANCELLED);
                return true;
            
            break;
        case R.id.remove_all_finished:
            if (state == TransferManager.TaskState.FINISHED) 
                mActivity.getTransferService().removeAllUploadTasksByState(TransferManager.TaskState.FINISHED);
                return true;
            
            break;
        default:
            return false;
    
    return false;

在fragment A中可以正常使用,当我长按fragment B时,它可以弹出菜单,这很好,但是当我选择菜单项时,它崩溃了。

崩溃日志是。

java.lang.IndexOutOfBoundsException: Invalid index 1, size is 0
        at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
        at java.util.ArrayList.get(ArrayList.java:308)
        at com.seafile.seadroid2.ui.adapter.TransferTasksAdapter.getItem(TransferTasksAdapter.java:131)
        at com.seafile.seadroid2.ui.adapter.TransferTasksAdapter.getItem(TransferTasksAdapter.java:32)
        at android.widget.AdapterView.getItemAtPosition(AdapterView.java:764)
        at com.seafile.seadroid2.ui.fragment.TransferTaskFragment.onContextItemSelected(TransferTaskFragment.java:186)
        at android.support.v4.app.Fragment.performContextItemSelected(Fragment.java:1593)
        at android.support.v4.app.FragmentManagerImpl.dispatchContextItemSelected(FragmentManager.java:2006)
        at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:370)
        at com.actionbarsherlock.app.SherlockFragmentActivity.onMenuItemSelected(SherlockFragmentActivity.java:210)

更新

此片段上用户可见提示的当前值。

为了解决问题,请在您的 Fragment 之一中添加条件,如下所示。

@Override
    public boolean onContextItemSelected(android.view.MenuItem item) 
        if (getUserVisibleHint()) 
            //TODO something when item was selected

            return true;
         else
            return false;
    

【问题讨论】:

菜单不是你的问题,你的问题在这里TransferTasksAdapter.java:131 是的,完全正确。但是当我单击上下文菜单项时,即使我在片段 B 中,它也总是转到片段 A。我喜欢由 listView.getItemAtPosition(info.position); 引起的错误,所以你知道如何做类似的事情,“我在片段 B 中,从 B 的适配器获取数据类型”,因为我总是使用 A。 【参考方案1】:

我刚刚遇到了同样的问题。但是我写的代码和你不一样。我在一个活动中有两个片段(这两个片段不从同一个祖先扩展),比如片段 A 和片段 B。(在 main_activity.xml 中,片段 A 在片段 B 之上,所以在 logcat 中,片段 A 总是在之前创建片段 B,我从片段 A 和片段 B 中的所有可调用函数中的 insert Log.d(...) 获得此信息) 片段A中有一个ListView,片段B中有一个GridView。 我在片段 onCreateView(..) 回调中调用了 registerForContextMenu(...),我还在片段 A 中覆盖了 onCreateContextMenu(..) 和 onContextItemSelected。 我在片段 B 中做了同样的事情。 现在问题来了: 1. 当我长按片段B中的项目(在gridview中)时,会调用片段B的onCreateContextMenu(我从日志信息中得到这个),然后我在弹出的上下文菜单中选择项目,很奇怪,片段A的onContextItemSelected被调用。 (由于片段B中的上下文菜单项与片段A中的上下文菜单项不同,有时整个应用程序崩溃,有时什么也没发生) 2. 当我在片段A中长按项目(在列表视图中)时,片段A的onCreateContextMenu被调用,然后我选择上下文项目,片段A的onContextItemSelected被调用。 因此,总的来说,片段 A 是有效的,片段 B 是无效的。我发现为了解决这个问题,我们应该在片段A中的onContextItemSelected中做更多的事情

公共布尔 onContextItemSelected(MenuItem menuItem) AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuItem.getMenuInfo(); 尝试 int 位置 = info.position; 最终 EditText et = (EditText) mListView.getChildAt(position).findViewById(R.id.edittext); 最终字符串名称 = et.getText().toString(); Log.d(TAG, "哈哈:" + 名字); 开关(menuItem.getItemId()) 案例 R.id.delete: SharedPreferences 首选项 = PreferenceManager.getDefaultSharedPreferences(mActivity); SharedPreferences.Editor 编辑器 = pref.edit(); editor.remove(name); editor.commit(); notifyDataSetChange(); 休息; 捕获(异常 e) 返回假; 返回真;

思路是当你发现选择的上下文项不是针对fragment A时,从fragment A的onContextItemSelected返回false,然后调用fragment B中的onContextItemSelected。

【讨论】:

我已经用解决方案更新了这个问题,希望对您有所帮助。 感谢分享!我有同样的问题,你的解决方案有效!在我的例子中,片段的每个实例中都有一个列表视图,我在两者上都调用了 registerForContextMenu。正如您所提到的 - OnCreateContextMenu 在正确的片段上被调用,但 OnContextMenuItemSelected 在错误的片段上被调用!【参考方案2】:

请使用下面的技巧对项目进行排序 在片段中使用的每个类中添加它

@Override
    public boolean onContextItemSelected(MenuItem item) 


 if(item.getTitle() == "Tittle you given to menu") 

// do somthing





【讨论】:

以上是关于上下文菜单不适用于两个片段的主要内容,如果未能解决你的问题,请参考以下文章

在 Ckeditor 5 中监听鼠标右键(上下文菜单)

在 Android 上禁用标注(上下文菜单)

在特定元素上禁用移动长按上下文菜单

onActivityResult 未在 Android API 23 的片段上调用

简单的计数器不适用于 React 上下文

Polly 的 Policy.TimeoutAsync 不适用于异步上下文中的 PolicyWrap