2012-07-17 4 views
5

Cela fait maintenant quelques jours que je joue avec cela et je n'arrive pas à le faire fonctionner. J'ai une activité qui affiche un fragment et ce fragment fait partie d'une liste de fragments que je consulte en utilisant ViewPager. Le fragment lui-même est composé d'un TextView et un ListView. Le ListView se remplit à partir d'un adaptateur personnalisé. Ce que j'essaye de faire est de passer un événement OnItemSelected au Fragment où il est manipulé. C'est probablement mieux pour moi d'aller de l'avant et de montrer du code ici.OnItemSelectedListener dans un fragment qui utilise un adaptateur personnalisé

C'est l'activité

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

C'est le Fragment:

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

Certaines lignes sont omises par souci de concision. Supposons que les Fragments soient affichés correctement et que tout fonctionne. La seule chose qui ne fonctionne pas correctement est que l'événement OnItemSelected dans l'activité ne se déclenche pas du tout ... et encore moins l'événement OnItemSelected dans le fragment. Qu'est-ce que je fais mal ici? Edit: les ListViews doivent être dans leurs Fragments respectifs (car ils seront affichés individuellement dans une activité différente ainsi que celle listée ci-dessus). Le plus gros problème ici est que je ne peux pas définir un OnItemSelectedListener dans mon Activity, par conséquent l'événement ne se déclenche jamais. J'ai tout le code menant à ce point travaillé et en cours d'exécution, c'est juste le OnItemSelectedListener qui ne fonctionne pas.

Edit2: Je vais ajouter une prime à cette question demain. À la lumière de cela, je pensais que je serais plus implicite sur la portée d'une réponse correcte. Une réponse correcte ne suggérerait aucun changement important dans la présentation ou la présentation de l'interface utilisateur. La réponse correcte transmet un événement OnItemSelected au fragment et y est traité. La réponse ne me ferait pas charger mon activité avec ligne après ligne de code pour réaliser quelque chose que je pense être faisable avec seulement quelques lignes. Les réponses les plus élégantes sont évidemment plus attrayantes. Merci à tous ceux qui y jettent un coup d'œil.

Le problème ici est que j'obtiens un NPE dans mon activité. Comment puis-je pointer vers un ListView qui existe dans une mise en page différente de celle de la classe dans laquelle il se trouve.

+2

courir le risque de casser votre « Je ne veux pas changer l'interface utilisateur » règle, est-il une raison que vous n'utilisez pas 'ListFragment' qui, par défaut, vous donne une méthode pour' Override' qui attrape les clics sur un 'ListView' et ainsi vous pouvez faire ce que je crois que vous essayez de faire, qui est de gérer les clics de l'élément de liste localement dans le fragment ... http://developer.android.com /reference/android/app/ListFragment.html#onListItemClick(android.widget.ListView, android.view.View, int, long) –

+0

oui, car le ListFragment remplit tout l'écran. Dans ce cas, je vais avoir des boutons en bas, et un titre TextView en haut – user1449018

+2

Vous semblez avoir des choses en arrière: vous ne devriez pas essayer d'attraper les clics de l'élément de liste dans l'activité et les propager au fragment (s), mais plutôt les recevoir directement dans le fragment concerné. Fondamentalement, @SalilPandit a donné la bonne approche. Si vous utilisez un 'ListFragment' ou non, c'est à vous de décider, mais votre supposition qu'il remplit tout l'écran n'est pas correcte; c'est juste un fragment de commodité pour traiter les listes, mais vous pouvez le faire ressembler à ce que vous voulez, à condition de déclarer au moins un 'ListView' avec' @android: id/list'. –

Répondre

2

Où utilisez-vous listView.setOnItemSelectedListener(this)? Vous devez informer explicitement ListView que votre activité devrait contrôler les comportements de l'interface utilisateur ...

Et dans votre Fragment ajouter:

listMain.setOnItemSelectedListener(this); 
+0

Oups. laissé cela. Modification op – user1449018

+0

Ok, maintenant vous devez trouver votre ListView dans l'activité (avec '(ListView) findViewById (R.id.listView)'), définissez l'adaptateur et faites de même. – Sam

+0

Je viens de l'essayer. Maintenant, je reçois NPE lors de la définition de l'écouteur à la liste dans l'activité. Je vais mettre à jour l'OP avec les changements de code – user1449018

0

J'ai aussi essayé de faire quelque chose de semblable à cela. Le problème réside dans le fait que vous n'avez pas d'instance dans l'activité avec laquelle définir un écouteur onitemselected. J'ai, personnellement, essayé tout ce que je pouvais penser pour que cela fonctionne. Y compris:

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

Où est la liste ListView vous instancier puis définissez à la liste dans le fragment. Le problème avec cette approche est que vous obtenez un NPE lorsque vous essayez de définir le programme d'écoute à cela. Si vous trouvez une réponse à cela s'il vous plaît, s'il vous plaît, postez le ici. Cela m'aiderait beaucoup.

J'ai eu des gens suggèrent que je prends une nouvelle approche et juste recréer la liste chaque fois que le viewpager est appelé (sans réellement pager..ie créer l'illusion d'un balayage alors qu'en réalité la vue ne change jamais) et j'ai eu des gens suggèrent d'utiliser un ListFragment ...ListFragment serait bien, mais vous ne pouvez rien ajouter d'autre dans votre mise en page, sauf un ListFragment.

+0

Merci pour votre contribution. Sam (ci-dessus) et moi avons travaillé dessus un moment et essayé plusieurs solutions mais rien ne semble fonctionner. Je pense presque que Android ne supporte pas la fonction comme ça. Ma dureté me dit que j'ai tort, et cela peut être fait. – user1449018

0

Dans votre FragmentActivity, au lieu d'utiliser OnItemSelectedListener, vous pouvez peut-être utiliser une méthode statique pour effectuer le travail. Et appelez cette méthode dans onItemSelected() (en fragment).

1

Créez votre propre interface et Callback est probablement la meilleure solution. Dans mon application, je l'ai fait quelque chose comme ceci:

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

Voici maintenant mon activité:

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

espérons qu'il vous aidera un peu. C'est la réponse la plus proche à votre question que je peux vous donner.

0

Implémenter une interface dans l'activité parente du fragment résoudra votre problème. Par exemple. Le TestFragment contient une interface appelée TestFragmentListener. Implémentez cette interface d'écouteur dans votre activité parente et maintenez la référence de l'interface dans le fragment pour exécuter la méthode callback.OnItemSelectedListener effectuez le rappel à l'activité parente et gérez le reste comme d'habitude. Veuillez vous référer à l'exemple de code ci-dessous.

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

} 
Questions connexes