web-dev-qa-db-fra.com

Meilleur endroit pour ajouterHeaderView dans ListFragment

J'ai quelques difficultés à configurer mon en-tête personnalisé dans ma liste.

Je crée un ListFragment avec un adaptateur personnalisé. La liste fonctionne bien, mais j'essaie de savoir où dans le cycle de vie d'un fragment joindre l'en-tête.

Je sais que l'en-tête doit être ajouté avant de configurer votre adaptateur.

J'ai essayé d'ajouter mon en-tête dans onActivityCreated, mais cet appel est appelé chaque fois que mon Fragment revient du backstack. Depuis que j'ai également configuré mon adaptateur dans onActivityCreated, il échoue.

J'ai essayé de l'ajouter à onCreate, mais la hiérarchie des vues n'était pas disponible à ce stade du cycle de vie.

J'ai essayé de l'ajouter à onCreateView, mais je ne pouvais pas convertir la vue renvoyée de gonfler en une liste. Donc, je ne pouvais pas ajouter mon en-tête à une vue Vanilla.

Des pensées?

34
brockoli

Je ne sais pas si vous avez résolu votre problème, mais voici une solution qui a fonctionné pour moi:

N'appelez pas ListFragment.setListAdapter() dans votre ListFragment.onCreate(). Assurez-vous de disposer d’une variable de champ pouvant contenir la vue d’en-tête, par exemple:

View mheaderView;

Puis, dans votre ListFragment.onCreateView(), gonflez l'en-tête View et affectez-le à votre variable comme suit

View list_root = inflater.inflate(R.layout.fragment_list, null);
// Get the list header - to be added later in the lifecycle
// during onActivityCreated()
mheaderView = inflater.inflate(R.layout.list_header, null);
return list_root;

Enfin, dans votre ListFragment.onActivityCreated(), vous pouvez maintenant appeler ListFragment.getListView().addHeaderView(). En gros, quelque chose comme ça:

super.onActivityCreated(savedInstanceState);
if (mheaderView != null)  this.getListView().addHeaderView(headerView);
// Don't forget to now call setListAdapter()
this.setListAdapter(listAdapter);
33
ugo

Cette solution fonctionne avec le retournement d'écran:

Dans onActivityCreated ():

getListView().addHeaderView(mHeaderView);
if (mMyAdapter == null) {
    mMyAdapter = new MyAdapter(getActivity(), null);
}
setListAdapter(mMyAdapter);

Et dans onDestroyView ()

setListAdapter(null);
32
delformo

Ma solution:

public void onActivityCreated(Bundle savedInstanceState) {
    setListAdapter(null);
    getListView().addHeaderView(mHeader);
    setListAdapter(mAdapter);
}
18
Jakob Eriksson

Comme solution courte qui a fonctionné pour moi:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    View headerView = getActivity().getLayoutInflater().inflate(R.layout.header, null);
    getListView().addHeaderView(headerView);

    ArrayAdapter<XY> mAdapter = createAdapter(); // create here your own adapter
    setListAdapter(mAdapter);
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    setListAdapter(null);
}
2

Ceci est ma solution pour gérer le pied de page/en-tête en vue liste. Je l'utilise en fragment retenu. L'adaptateur est initialisé dans la méthode renderView (). Cette méthode peut être appelée combien de fois vous avez besoin (par exemple pour actualiser les données dans la vue) et le pied de page/en-tête fonctionne correctement. J'ai testé ce code sur Android 2,3,4. 

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    super.onActivityCreated(savedInstanceState);

    ...

    renderView();
}


@Override
public void onDestroyView()
{
    super.onDestroyView();

    // free adapter
    setListAdapter(null);
}


private void renderView()
{
    // reference
    ListView listView = getListView();

    // adapter
    if(getListAdapter()==null)
    {
        // init adapter
        mAdapter = new MyAdapter(...);
    }
    else
    {
        // refill adapter
        // this method assign array list object to adapter and call notifyDataSetChanged()
        mAdapter.refill(...);
    }

    // add footer
    setListAdapter(null);
    if(listView.getFooterViewsCount()==0)
    {
        mFooterView = getActivity().getLayoutInflater().inflate(R.layout.my_footer, null);
        listView.addFooterView(mFooterView);
    }

    // set adapter
    setListAdapter(mAdapter);
}
2
petrnohejl

J'utilise actuellement la solution suivante dans ma classe qui étend ListFragment:

1) Dans votre classe onActivityCreated, vous vérifiez si votre adaptateur (qui est une variable de classe) est null, puis vous l'instanciez. Ensuite, gonflez le pied de page, par exemple comme ceci:

View footerView = View.inflate
    (getActivity(), R.layout.list_footer_loader_view, null);

Vous n'avez qu'à le faire une fois! FooterView et l'adaptateur ne doivent être créés qu'une seule fois. Je crée ces deux éléments dans ma onActivityCreated

Passons maintenant à la "partie difficile", définissez votre fragment dans votre onCreate comme suit:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
}

J'aime bien le faire dans la onCreate car ce n'est pas pertinent pour l'activité. Désormais, avec setRetainInstance(true), votre fragment ne sera pas recréé une fois l’activité détruite, événement tel que l’orientation de l’écran.

Maintenant, après ces lignes, ajoutez le pied de page comme ceci:

getListView().addFooterView(footerView);

Et puis connectez l'adaptateur à la liste:

setListAdapter(adapter);

Cela devrait être fait chaque fois que l'activité meurt, faites ceci dans onActivityCreated.

Et l'une des autres choses importantes à laquelle vous devriez généralement penser quand il s'agit de fragmenter est de ne pas créer le fragment à chaque fois que la variable onCreate de l'activité est appelée.

Par exemple, faites ceci (si votrePASen utilisant le supportpackage):

MyFragment myFragment  = (MyFragment)
    getFragmentManager().findFragmentByTag(tag);
if (myFragment == null) {
    myFragment = MyFragment.newInstance();
    getFragmentManager().beginTransaction().
            add(myFragment, tag).commit();
}

Cela ne créera le fragment qu'une seule fois, si la balise est unique pour ce fragment bien sûr. 

0
Johan S

J'ai eu quelques problèmes avec la hauteur de la disposition de l'en-tête, j'ai donc suivi cette solution :

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setListAdapter(null);//avoid problems with orientation changes
    header = getActivity().getLayoutInflater().inflate(R.layout.row_diario_header,getListView(),false);
    getListView().addHeaderView(header);
    ArrayList<Notificacao> nots = new ArrayList<>();

    nots.add(new Notificacao("16/04/2015", "Test", "Erro"));
    setListAdapter(new DiarioAdapter(getActivity(), R.layout.listview_diario, nots));
}

Header est une instance de View et DiarioAdapter est un ArrayAdapter personnalisé.

MISE À JOUR 1

Si vous rencontrez des problèmes avec le duplicata listfragment, il suffit de changer FragmentTransaction ADD for REPLACE.

0
Beto Caldas