2012-07-17 17 views
5

Así que he estado jugando con esto durante unos días y parece que no funciona. Tengo una Actividad que muestra un Fragmento y ese Fragmento es un miembro de una lista de Fragmentos que publico usando ViewPager. El Fragmento en sí está compuesto por un TextView y un ListView. ListView se rellena desde un Adaptador personalizado.OnItemSelectedListener en un fragmento que usa un adaptador personalizado

Lo que intento hacer es pasar un evento OnItemSelected al Fragmento donde se maneja. Probablemente sea mejor para mí seguir adelante y mostrar el código aquí.

Esta es la actividad

public class DialogInventory extends FragmentActivity implements OnItemSelectedListener { 

ViewPager viewPager; 
Pager pager; 

@Override 
protected void onCreate(Bundle bundle) { 
    super.onCreate(bundle); 
    setContentView(R.layout.dialog_inventory); 

    List<Fragment> fragList = new Vector<Fragment>(); 
    fragList.add(Fragment.instantiate(this, FragmentOne.class.getName())); 
    fragList.add(Fragment.instantiate(this, FragmentTwo.class.getName())); 
    pager = new Pager(getSupportFragmentManager(), fragList); 

    viewPager = (ViewPager) findViewById(R.id.pagerMain); 
    viewPager.setAdapter(pager); 

    listMain = (ListView) findViewById(R.id.listMain); 
    listMain.setOnItemSelectedListener(this); 
} 

public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 
    switch (viewPager.getCurrentItem()) { 
     case 0: 
      FragmentOne fragOne = new FragmentOne(); 
      fragOne.onItemSelected(parent, view, pos, id); 
      break; 
     case 1: 
      FragmentTwo fragTwo = new FragmentTwo(); 
      fragTwo.onItemSelected(parent, view, pos, id); 
      break; 
    } 
} 
public void onNothingSelected(AdapterView<?> arg0) { 
} 

Este es el fragmento:

public class FragmentOne extends Fragment implements OnItemSelectedListener { 

View view; 
ListView listMain; 
ArrayList<String> invItems = new ArrayList<String>(); 

public FragmentOne() { 
} 
@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) { 
    view = inflater.inflate(R.layout.fragment_one, viewGroup, false); 

    listMain = (ListView) v.findViewById(R.id.listMain); 
    listMain.setAdapter(new AdapterItem(getActivity().getApplicationContext(), 
     R.layout.tile_item, invItems)); 
    listMain.setOnItemSelectedListener(this); 
    return view; 
} 
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 
    Log.i("Test", "hit"); 
} 

Algunas líneas se omiten por razones de brevedad. Vamos a suponer que los Fragmentos se muestran correctamente y que todo funciona. Lo único que no funciona correctamente es que el evento OnItemSelected en la actividad no se activa en absoluto ... mucho menos el evento OnItemSelected en el fragmento. ¿Qué estoy haciendo mal aquí?

Editar: las ListViews deben estar en sus respectivos Fragmentos (ya que se mostrarán individualmente en una Actividad diferente, así como la que se menciona arriba). El mayor problema aquí es que no puedo establecer un OnItemSelectedListener en mi actividad, por lo tanto, el evento nunca se dispara. Tengo todo el código que conduce a ese punto elaborado y en funcionamiento, es solo el OnItemSelectedListener que no funciona.

Edit2: Voy a agregar una recompensa a esta pregunta mañana. A la luz de eso, pensé que estaría más implícito en el alcance de una respuesta correcta. Una respuesta correcta no sugiere cambios drásticos en el diseño o la presentación de la interfaz de usuario. La respuesta correcta pasará un evento OnItemSelected al Fragmento y se manejará allí. La respuesta no me haría cargar mi actividad con una línea tras otra de código para lograr algo que creo que se puede hacer con solo unas pocas líneas. Las respuestas más elegantes son obviamente más atractivas. Gracias a todos los que miran esto.

El problema aquí es que obtengo un NPE en mi actividad. ¿Cómo apunto a un ListView que existe en un diseño diferente que el Diseño de la clase en la que se encuentra.

+2

correr el riesgo de romper su "No quiero cambiar la interfaz de usuario" regla, hay una razón por la que no está utilizando un 'ListFragment' que por defecto le da un método para' Override' que capta los clics en un 'ListView' y así puede hacer lo que creo que está tratando de hacer, que es manejar los clics de los elementos de la lista localmente en el fragmento ... http://developer.android.com /reference/android/app/ListFragment.html#onListItemClick(android.widget.ListView, android.view.View, int, long) –

+0

sí, porque ListFragment llena toda la pantalla. En este caso, tendré botones en la parte inferior y un título TextView en la parte superior. – user1449018

+2

Parece que tiene las cosas en orden: no debería tratar de captar los clics de elementos de la lista en la actividad y propagarlos al fragmento (s), sino más bien recíbalos en el fragmento relevante directamente. Básicamente @SalilPandit ha dado el enfoque correcto. Si usted usa un 'ListFragment' o no depende de usted, su suposición de que" llena la pantalla completa "no es correcta; es solo un fragmento de conveniencia para tratar con listas, pero puede hacer que parezca lo que quiera, siempre que al menos declare un 'ListView' con' @android: id/list'. –

Respuesta

2

¿Dónde se usa listView.setOnItemSelectedListener(this)? Es necesario informar explícitamente el ListView que su actividad debe controlar los comportamientos de interfaz de usuario ...

Y en su Fragmento añadir:

listMain.setOnItemSelectedListener(this); 
+0

Ooops. lo dejé fuera. Editando op – user1449018

+0

Ok, ahora necesitas encontrar tu ListView en la Actividad (con '(ListView) findViewById (R.id.listView)'), configura el adaptador y haz lo mismo. – Sam

+0

Solo lo probé. Ahora estoy obteniendo NPE al configurar el oyente a la vista de lista en la actividad. Actualizaré el OP con los cambios de código – user1449018

0

También he estado tratando de hacer algo similar a esto. El problema radica en el hecho de que no tiene una instancia en la actividad para establecer un oyente seleccionado en un momento. Personalmente, probé todo lo que pude pensar para que esto funcione. Incluyendo:

list = (ListView) vp.getRootView().findViewById(R.id.listMain); 
list.setOnItemSelectedListener(this); 

Donde la lista es una vista de lista que crea una instancia y luego establece la lista en el fragmento. El problema con este enfoque es que obtienes un NPE cuando tratas de configurar al oyente para esto. Si encuentra una respuesta a esto, por favor, por favor publíquelo aquí. Me ayudaría muchísimo.

He tenido personas que sugieran que adopte un nuevo enfoque y simplemente vuelva a crear la lista cada vez que se llame al viewpager (sin realmente paginación ... creando la ilusión de deslizar cuando en realidad la vista nunca cambia) y he tenido personas que sugieren usar un ListFragment ...ListFragment sería agradable, pero luego no puede incluir nada más en su diseño, excepto un ListFragment.

+0

Gracias por la entrada. Sam (arriba) y trabajé en esto un poco y probé varias soluciones pero nada parece funcionar. Casi estoy pensando que Android no admite funciones como esta. Mi testarudez me dice que estoy equivocado, y esto se puede hacer. – user1449018

0

En su FragmentActivity, en lugar de usar OnItemSelectedListener, quizás pueda usar un método estático para hacer el trabajo. Y llame a este método en onItemSelected() (en fragmento).

1

Cree su propia interfaz y Callback es probablemente la mejor solución. En mi aplicación hice algo como esto:

public class ModuleFragment extends ListFragment { 
    //... 
    private OnModuleSelectedListener mdListener; 

// this method makes sure my activity implements my interface. If not I show an error 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     try { 
      mdListener = (OnModuleSelectedListener) activity; 
      Log.d(TAG, "OnModuleSelectedListener Implemented !"); 
     } catch (ClassCastException e) { 
      throw new ClassCastException(activity.toString() 
       + " must implement OnSqSelectedListener"); 
     } 
    } 
// This is the standard onListItemClick, I use it to get data I need and give them to the Listener 
    public void onListItemClick(ListView l, View v, int position, long id) { 
     super.onListItemClick(l, v, position, id); 
     l.getItemAtPosition(position); 
     HashMap<String, String> map = (HashMap<String, String>) l 
      .getItemAtPosition(position); 
     mdId = map.get("id"); 
     mdName = map.get("name"); 
     mdListener.onModuleSelected(mdId,mdName); 

    } 

    public interface OnModuleSelectedListener { 
     public void onModuleSelected(String mdId, String mdName); 
    } 
} 

He aquí ahora mi actividad:

public class Main extends Activity implements OnModuleSelectedListener{ 
//... 
    public void onModuleSelected(String mdId, String mdName) { 
      //.. I do whatever I want with what I get from the list 
    } 
} 

espero que le ayuda un poco. Esa es la respuesta más cercana a su pregunta que puedo darle.

0

Implementar una interfaz en la actividad padre del fragmento resolverá su problema. Por ejemplo. TestFragment contiene una interfaz llamada TestFragmentListener. Implemente esta interfaz de escucha en su actividad principal y mantenga la referencia de la Interfaz en el Fragmento para hacer la devolución de llamada. El método de EnumeraciónSelección de Oyente realiza la devolución de llamada a la actividad principal y maneja el resto como es normal. Por favor, consulte el código de muestra a continuación.

public final class TestFragment extends Fragment { 

    TextView title; 
    ListView listView; 
    TestFragmentListener mActivity; 
    TestAdapter adapter; 

    public interface TestFragmentListener { 
     public void onItemSelected(Object o); 
    } 

    public static TestFragment newInstance(String content) { 
     TestFragment fragment = new TestFragment(); 
     return fragment; 
    } 

    @Override 
    public void onAttach(Activity activity) { 

     try { 
      mActivity = (TestFragmentListener) activity; 

     } catch (ClassCastException e) { 
      Log.e("Invalid listerer", e.getMessage()); 
     } 

     super.onAttach(activity); 
    } 

    @Override 
    public void onDetach() { 
     super.onDetach(); 
     mActivity = null; 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 

     View vw = inflater.inflate(R.layout.layout, container, false); 

     title = (TextView) vw.findViewById(R.id.textView1); 
     listView = (ListView) vw.findViewById(R.id.listView1); 

     return vw; 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 

     TestAdapter adapter = new TestAdapter(); 

     listView.setAdapter(adapter); 

     listView.setOnItemClickListener(new OnItemClickListener() { 

      public void onItemClick(AdapterView<?> arg0, View arg1, 
        int position, long arg3) { 
      } 
     }); 

     listView.setOnItemSelectedListener(new OnItemSelectedListener() { 

      @Override 
      public void onItemSelected(AdapterView<?> arg0, View arg1, 
        int arg2, long arg3) { 
       mActivity.onItemSelected(arg2); 

      } 

      @Override 
      public void onNothingSelected(AdapterView<?> arg0) { 
       // TODO Auto-generated method stub 

      } 
     }); 
     super.onActivityCreated(savedInstanceState); 
    } 

private class TestAdapter extends BaseAdapter { 

     @Override 
     public int getCount() { 
      return 100; 
     } 

     @Override 
     public Object getItem(int arg0) { 
      return null; 
     } 

     @Override 
     public long getItemId(int arg0) { 
      return arg0; 
     } 

     @Override 
     public View getView(int position, View convertView, ViewGroup container) { 

      TextView tv = new TextView((Activity) mActivity); 
      tv.setText(Integer.toString(position)); 
      return tv; 
     } 
    } 

} 
Cuestiones relacionadas