2012-03-17 12 views
22

Tengo una aplicación que muestra algunos fragmentos (del mismo tipo) en un ViewPager y tengo problemas con los elementos del menú contextual. (Estoy usando la biblioteca de soporte).Fragmento incorrecto en ViewPager recibe onContextItemSelected call

Cuando se selecciona un elemento del menú contextual en el menú contextual en uno de los fragmentos, el fragmento incorrecto recibe la llamada al evento onContextItemSelected.

Por ejemplo, si estoy en el fragmento n. ° 3 en el localizador, el fragmento en la posición n. ° 2 lo recibe en su lugar. Si vuelvo al fragmento n. ° 2, el fragmento n. ° 3 recibe la llamada.

Tengo una muestra here.

(Actualmente estoy trabajando en esto en mi propia aplicación teniendo una variable mHandleContext en cada fragmento y habilitándola/deshabilitándola cuando la página se cambie. De esta forma, la llamada onContextItemSelected saldrá a todos los fragmentos hasta la derecha uno se llama.)

¿Estoy haciendo algo mal o es esto un error con la biblioteca de soporte? Como nota al margen, esto no sucedió cuando estaba usando ActionBarSherlock 3.5.1, que tenía su propio tenedor de la biblioteca de soporte.

+1

posible duplicado de [Cómo manejar onContextItemSelected en una actividad de múltiples fragmento] (http://stackoverflow.com/questions/5297842/how-to-handle-oncontextitemselected-in-a-multi-fragment-activity) –

Respuesta

33

Así que esto es una especie de decisión de diseño idiota por Google o algo así, que ya pasó totalmente desconsiderada. La forma más sencilla de evitar esto es para envolver la llamada onContextItemSelected con una sentencia if como esta: biblioteca

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

La compatibilidad en ActionBarSherlock 3.5 tenía un corte como este.

+1

@Seraph la respuesta parece ser más correcta, tan pronto como haya una explicación de este comportamiento. Tuve el mismo problema y lo resolví utilizando diferentes ID de grupo (como en su solución) para los menús contextuales de diferentes fragmentos – marwinXXII

+0

Arnt 'sugerencia' considerada no confiable? –

+0

Teóricamente, tal vez, pero ambos adaptadores de fragmentos para ViewPager establecen los consejos. – Veeti

14

Sucede debido a esto:

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

Como se puede ver, FragmentManager llama Fragment.onContextItemSelected para todos sus propios fragmentos hasta que vuelve verdadera. En el ejemplo que puede ofrecer dicha solución:

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

} 
+0

Intenté esto y parece que no funciona. item.getGroupId() devuelve 0 sin importar en qué fragmento se haga clic con el botón largo. –

+0

Es una gran idea usar groupID para este propósito. Esa es definitivamente la mejor respuesta. – YBrush

0

Oh Google, me refiero a WTF?

El problema es que onContextItemSelected es muy genérico, y se llama para cada elemento del menú de cada fragmento.

Usted puede utilizar MenuItem.OnMenuItemClickListener para forzar menú fragmento de no utilizar toda onContextItemSelected, pero sólo misma función de este fragmento.

Uso próxima aplicación:

@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: 
     // ... 
    } 
} 
0

El uso de intención para cada uno de los elementos del menú funcionó bien para mí.

@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); 
    } 
Cuestiones relacionadas