2012-07-17 19 views
5

Così ho giocato con questo per alcuni giorni e proprio non riesco a farlo funzionare. Ho un'attività che visualizza un frammento e quel frammento è un membro di un elenco di frammenti che ho sfogliato usando ViewPager. Il frammento stesso è composto da un TextView e un ListView. ListView si popola da un adattatore personalizzato.OnItemSelectedListener in un frammento che utilizza un adattatore personalizzato

Quello che sto cercando di fare è passare un evento OnItemSelected al Frammento in cui viene gestito. Probabilmente è meglio per me andare avanti e mostrare il codice qui.

Questa è l'attività

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) { 
} 

Questo è il frammento:

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

Alcune linee sono omesse per brevità. Partiamo dal presupposto che i Frammenti vengano visualizzati correttamente e che tutto funzioni. L'unica cosa che non funziona correttamente è che l'evento OnItemSelected nell'Attività non sta sparando affatto ... tanto meno l'evento OnItemSelected nel frammento. Cosa sto facendo di sbagliato qui?

Modifica: le ListViews devono essere nei rispettivi frammenti (in quanto verranno visualizzati singolarmente in un'attività diversa, oltre a quella elencata sopra). Il problema più grande qui è che non posso impostare un OnItemSelectedListener nella mia attività, quindi l'evento non viene mai sparato. Ho tutto il codice che porta a quel punto elaborato e funzionante, è solo l'OnItemSelectedListener che non funziona.

Edit2: Domani aggiungerò una taglia a questa domanda. Alla luce di ciò ho pensato che sarei stato più implicito nello scopo di una risposta corretta. Una risposta corretta non suggerirebbe modifiche radicali al layout o alla presentazione dell'interfaccia utente. La risposta corretta passerà un evento OnItemSelected al Fragment e verrà gestito lì. La risposta non mi permetterebbe di caricare la mia attività con una riga dopo l'altra del codice per ottenere qualcosa che ritengo possa fare solo poche righe. Le risposte più eleganti sono ovviamente più accattivanti. Grazie a tutti coloro che danno un'occhiata a questo.

Il problema qui è che ottengo un NPE nella mia attività. Come faccio a puntare a un ListView che esiste in un layout diverso rispetto al Layout della classe in cui è.

+2

correre il rischio di rompere il vostro "Io non voglio cambiare l'interfaccia utente" regola, c'è una ragione per cui non si utilizza un 'ListFragment' che di default fornisce un metodo per' Override' che cattura i clic su un 'ListView' e quindi puoi fare ciò che credo tu stia cercando di fare, ovvero gestire gli elementi della lista cliccando localmente nel frammento ... http://developer.android.com /reference/android/app/ListFragment.html#onListItemClick(android.widget.ListView, android.view.View, int, long) –

+0

sì, perché il ListFragment riempie l'intero schermo. In questo caso avrò i pulsanti in basso e il titolo TextView in alto – user1449018

+2

Sembra che le cose stiano andando in primo piano: non dovresti cercare di catturare i clic dell'elemento dell'elenco nell'attività e propagarli al frammento (s), ma piuttosto riceverli direttamente nel relativo frammento. Fondamentalmente @SalilPandit ha dato l'approccio corretto. Sia che tu usi un 'ListFragment' o no dipende da te, ma il tuo presupposto che lo schermo" riempie tutto "non è corretto; è solo un comodo frammento per gestire gli elenchi, ma puoi farlo sembrare come vuoi, purché tu dichiari almeno un 'ListView' con' @android: id/list'. –

risposta

2

Dove usi listView.setOnItemSelectedListener(this)? È necessario informare in modo esplicito il ListView che il vostro attività dovrebbe controllare i comportamenti UI ...

E nel tuo Frammento aggiungere:

listMain.setOnItemSelectedListener(this); 
+0

Ooops. lasciato fuori. Editing op – user1449018

+0

Ok, ora devi trovare il tuo ListView in Activity (con '(ListView) findViewById (R.id.listView)'), imposta l'adattatore e fai lo stesso. – Sam

+0

Ho appena fatto un tentativo. Ora sto ricevendo NPE su come impostare l'ascoltatore per la listview nell'attività. Aggiornerò l'OP con le modifiche al codice – user1449018

0

Ho anche cercato di fare qualcosa di simile a questo. Il problema sta nel fatto che non hai un'istanza nell'attività con cui impostare un ascoltatore onitemselected. Io, personalmente, ho provato tutto quello che potevo pensare per farlo funzionare. Tra cui:

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

Dove lista è un ListView si crea un'istanza quindi impostare alla lista nel frammento. Il problema con questo approccio è che si ottiene un NPE quando si tenta di impostare il listener su questo. Se trovi una risposta a questo, per favore, per favore postala qui. Mi avrebbe aiutato un sacco.

Ho avuto la gente suggerire che prendo un nuovo approccio e appena ricreare l'elenco ogni volta che viene chiamato il viewpager (senza effettivamente paging..ie creando l'illusione di un passaggio quando in realtà la vista non cambia mai) e ho avuto persone suggeriscono di usare un ListFragment ...ListFragment sarebbe bello, ma non puoi includere nient'altro nel tuo layout ad eccezione di ListFragment.

+0

Grazie per l'input. Sam (sopra) e ho lavorato su questo per un po 'e provato diverse soluzioni, ma niente sembra funzionare. Sto quasi pensando che Android non supporti funzioni come questa. La mia testardaggine mi dice che mi sbaglio, e questo può essere fatto. – user1449018

0

In FragmentActivity, invece di utilizzare OnItemSelectedListener, è possibile utilizzare un metodo statico per eseguire il lavoro. E chiamare questo metodo in onItemSelected() (in frammento).

1

Creare la propria interfaccia e il callback è probabilmente la soluzione migliore. Nella mia app che ho fatto qualcosa di simile:

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

Ecco ora la mia attività:

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

Spero che ti aiuta un po '. Questa è la risposta più vicina alla tua domanda che posso darti.

0

Implementare un'interfaccia nell'attività principale del frammento risolverà il problema. Per esempio. TestFragment contiene un'interfaccia denominata TestFragmentListener. Implementare questa interfaccia listener nell'attività principale e conservare il riferimento dell'interfaccia nel frammento per eseguire il callback.OnItemSelectedListener metodo effettua il callback dell'attività parent e gestisce il resto normalmente. Si prega di fare riferimento al codice di esempio qui sotto.

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

} 
Problemi correlati