25

いくつかの (同じタイプの) フラグメントを表示するアプリがあり、ViewPagerコンテキスト メニュー項目に問題があります。(サポートライブラリを使用しています)。

いずれかのフラグメントのコンテキスト メニューでコンテキスト メニュー項目が選択されると、間違ったフラグメントがonContextItemSelectedイベント呼び出しを受け取ります。

たとえば、ページャーでフラグメント #3 を使用している場合、代わりに位置 #2 のフラグメントがそれを受け取ります。スワイプしてフラグメント #2 に戻すと、代わりにフラグメント #3 が通話を受信します。

ここにサンプルがあります。

(私は現在mHandleContext、各フラグメントに変数を持ち、ページが変更されたときにそれを有効/無効にすることで、自分のアプリでこれを回避しています。そうonContextItemSelectedすれば、正しいフラグメントが呼び出されるまで、すべてのフラグメントに呼び出しが送信されます。)

何か間違ったことをしていますか、それともサポート ライブラリのバグですか? 補足として、サポート ライブラリの独自のフォークを持つ ActionBarSherlock 3.5.1 を使用していたときには、これは発生しませんでした。

4

5 に答える 5

37

つまり、これは Google によるばかげた設計上の決定であるか、まったく考慮されていないものです。これを回避する最も簡単な方法は、onContextItemSelected次のような if ステートメントで呼び出しをラップすることです。

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

ActionBarSherlock 3.5 の互換性ライブラリには、このようなハックがありました。

于 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 は true が返されるまで、自身のすべてのフラグメントに対して Fragment.onContextItemSelected を呼び出します。あなたの例では、そのような修正を提供できます:

    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 に答える
0

ああ、Google、つまり 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 に答える