25

我有一个应用程序在 a 中显示了一些片段(相同类型),ViewPager并且我在上下文菜单项方面遇到了一些问题。(我正在使用支持库)。

当在其中一个片段的上下文菜单中选择上下文菜单项时,错误的片段正在接收onContextItemSelected事件调用。

例如,如果我在寻呼机中的片段#3 上,则位置#2 的片段会接收它。如果我滑回片段#2,片段#3 会接收到呼叫。

这里有一个样品。

(我目前正在我自己的应用程序中解决这个问题,方法是mHandleContext在每个片段中都有一个变量,并在页面更改时启用/禁用它。这样,onContextItemSelected调用将发送到所有片段,直到调用正确的片段。)

我做错了什么还是支持库的错误?附带说明一下,当我使用 ActionBarSherlock 3.5.1 时,这并没有发生,它有自己的支持库的分支。

4

5 回答 5

37

所以这是谷歌的某种愚蠢的设计决定,或者是完全没有考虑的事情。解决此问题的最简单方法是使用这样的 if 语句包装onContextItemSelected调用:

if (getUserVisibleHint()) {
    // Handle menu events and return true
} else
    return false; // Pass the event to the next fragment

ActionBarSherlock 3.5 中的兼容性库有这样的 hack。

于 2012-04-15T13:28:00.387 回答
14

之所以会这样,是因为:

public boolean dispatchContextItemSelected(MenuItem item) {
    if (mActive != null) {
        for (int i=0; i<mAdded.size(); i++) {
            Fragment f = mAdded.get(i);
            if (f != null && !f.mHidden) {
                if (f.onContextItemSelected(item)) {
                    return true;
                }
            }
        }
    }
    return false;
}

如您所见,FragmentManager 为他自己的所有 Fragment 调用 Fragment.onContextItemSelected 直到它返回 true。在您的示例中,我可以提供这样的修复:

    public static class TestListFragment extends ListFragment {

    private int mNumber = 0;
    private ArrayList<String> mItems;

    public static TestListFragment newInstance(int number) {
        Bundle args = new Bundle();
        args.putInt("number", number + 1);

        TestListFragment fragment = new TestListFragment();
        fragment.setArguments(args);

        return fragment;
    }

    public TestListFragment() {}

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mNumber = getArguments().getInt("number");
        mItems = new ArrayList<String>();
        mItems.add("I am list #" + mNumber);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mItems));
        registerForContextMenu(getListView());
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.add(mNumber, 0, 0, "Hello, World!");
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        if(item.getGroupId() == mNumber){
            Log.d("ViewPagerContextMenuBug", "onContextItemSelected called for number " + mNumber);
            Toast.makeText(getActivity(), "onContextItemSelected called for number " + mNumber, Toast.LENGTH_SHORT).show();
            return true;
        }
        return false;
    }

}
于 2012-03-17T20:38:21.200 回答
1

对每个菜单项使用意图对我来说效果很好。

    @Override  
    public void onCreateContextMenu(ContextMenu menu, View v, ContextmenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);

        MenuInflater inflater = super.getActivity.getMenuInflater();

        inflater.infalte(R.menu.list_item, menu);

        for(int i = 0; i < menu.size(); i++) {
            MenuItem item = menu.getItem(i);
            Intent intent = new Intent();
            intent.putExtra(KEY_EXTRA_FRAGMENT_ID, this.fragmentId);
            if (item != null) {
                item.setIntent(intent);
            }
        }
    }

    @Override
    public boolean onContextItemSelected(MeniItem item) {

        Intent intent = item.getIntent();

        if (intent != null) {
            if (intent.getIntExtra(KEY_EXTRA_FRAGMENT_ID, -1) == this.fragmentId) {

                // Implement code according the item function.

                return true;
            }
        }

        return super.onContextItemSelected(item);
    }
于 2017-04-05T12:05:39.317 回答
1

getUserVisibleHint()解决方案对我不起作用 -true即使片段不在屏幕上,它也总是返回。从 XML 资源扩充菜单时,该getGroupId()解决方案也不起作用,这是我的情况。

似乎除非 Android 发生变化,否则任何解决方案总是会有点 hacky。我创建了一个全局变量来将当前片段的 ID 引用存储在onCreateView. 然后我将它传递给ContextMenu MenuItem. onCreateContextMenu选择项目后,我验证这两个ID是相同的。

private int myFragmentReference;

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Initialisation stuff

    myFragmentReference = 12345;
}

@Override
public void onCreateContextMenu(ContextMenu contextMenu, View v, ContextMenu.ContextMenuInfo contextMenuInfo) {
    // Usual stuff

    int size = contextMenu.size();
    for (int i = 0; i < size; i++) {
        MenuItem menuItem = contextMenu.getItem(i);
        Intent intent = new Intent();
        intent.putExtra("id", myFragmentReference);
        menuItem.setIntent(intent);
    }
}

@Override
public boolean onContextItemSelected(MenuItem menuItem) {
    int id = 0;
    Intent intent = menuItem.getIntent();
    if (intent != null) {
        id = intent.getIntExtra("id", 0);
    }
    if (id == myFragmentReference) {
        // This is the currently displayed fragment
    }
}
于 2018-04-21T09:40:04.277 回答
0

哦,谷歌,我的意思是 WTF?

问题是onContextItemSelected非常通用,每个片段的每个菜单项都会调用它。

您可以使用MenuItem.OnMenuItemClickListener强制片段菜单不使用所有 onContextItemSelected,而仅使用该片段的相同功能。

使用下一个实现:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    MenuInflater inflater = getActivity().getMenuInflater();
    if (v == btnShare) {
        inflater.inflate(R.menu.share_menu, menu);
        for (int i = 0; i < menu.size(); ++i) {
            MenuItem item = menu.getItem(i);
            item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    onContextItemSelected(item);
                    return true;
                }
            });
        }
    }
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    switch (item.getItemId()) {
        case R.id.print:
        // ...
    }
}
于 2017-01-11T15:53:12.730 回答