Най-доброто място за добавяне на HeaderView в ListFragment

Имам известен проблем с настройването на персонализираната ми заглавка в моя списък.

Създавам ListFragment с персонализиран адаптер. Списъкът ми работи добре, но се опитвам да разбера къде в жизнения цикъл на фрагмент да прикача заглавката.

Знам, че заглавката трябва да се добави, преди да настроите адаптера си.

Опитах се да добавя заглавката си в onActivityCreated, но това се извиква всеки път, когато моят фрагмент се върне от задния стек, и тъй като също така зададох своя адаптер в onActivityCreated, той се проваля.

Опитах се да го добавя в onCreate, но йерархията на изгледите не е налична на този етап от жизнения цикъл.

Опитах се да го добавя в onCreateView, но не можах да прехвърля изгледа, върнат от inflate, към ListView. Така че не можах да добавя моя хедър към ванилен изглед.

някакви мисли?


person brockoli    schedule 18.04.2011    source източник


Отговори (7)


Не знам дали сте решили проблема си, но ето едно решение, което работи за мен:

Не се обаждайте на ListFragment.setListAdapter() във вашия ListFragment.onCreate(). Уверете се, че имате променлива на полето, която може да поддържа изгледа на заглавката, може би като:

View mheaderView;

След това във вашия ListFragment.onCreateView() раздуйте заглавния изглед и го присвоете на вашата променлива по следния начин:

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;

И накрая, във вашия ListFragment.onActivityCreated() вече можете да се обадите на ListFragment.getListView().addHeaderView(). По принцип нещо подобно:

super.onActivityCreated(savedInstanceState);
if (mheaderView != null)  this.getListView().addHeaderView(headerView);
// Don't forget to now call setListAdapter()
this.setListAdapter(listAdapter);
person ugo    schedule 01.06.2011
comment
Това не работи за мен - получавам срив при обръщане на екрана, когато се оплаква от присвояване на изглед на заглавка към списък, след като съм извикал setListAdapter. - person Eric Mill; 14.11.2011
comment
Аз също съм изправен пред същия проблем. в тези два метода на моя фрагмент - person Naveen Chauhan; 11.06.2012
comment
Какво ще кажете за надуване на заглавката, добавяне и setListAdapter в onViewCreated? - person dvd; 05.08.2012
comment
За всеки, който има проблеми като Konklone и Naveen Chauhan: извикването на setListAdapter(null) във вашия onDestroyView трябва да свърши работа. - person Rad Haring; 27.06.2014

Това решение работи с обръщане на екрана:

В onActivityCreated():

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

И в onDestroyView()

setListAdapter(null);
person delformo    schedule 15.11.2011
comment
Благодаря тази помощ ми. И мисля, че това е грешка в ListFragment и трябва да се справи сам. - person ATom; 08.02.2012
comment
благодаря, важно е да се отбележи, че трябва да настроите ListAdapter на null в onDestroyView - person martyglaubitz; 30.10.2012
comment
Имах същите проблеми и ги разреших след добавяне на 'setListAdapter(null);' към onDestroyView() - person mutable2112; 25.06.2013
comment
след setListAdapter(null) в onDestroyView ... когато се върна към моя фрагмент, той показва само празния изглед, но зададох нов адаптер към моя listview!! .. някаква помощ ? - person mnagy; 12.02.2014

Моето решение:

public void onActivityCreated(Bundle savedInstanceState) {
    setListAdapter(null);
    getListView().addHeaderView(mHeader);
    setListAdapter(mAdapter);
}
person Jakob Eriksson    schedule 06.04.2012
comment
Това изглежда като най-чистото решение. - person louielouie; 22.05.2012
comment
onActivityCreated() изглежда е най-доброто място за настройка на onScrollListener(). - person user1549672; 05.04.2015

Това е моето решение за работа с долен/заглавен колонтитул в списъчен изглед. Използвам го в запазен фрагмент. Адаптерът се инициализира в метода renderView(). Този метод може да бъде извикан колко пъти имате нужда (напр. за опресняване на данните в изгледа) и долен/заглавен колонтитул работи добре. Тествах този код на 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);
}
person petrnohejl    schedule 20.10.2012

Като кратко решение, което работи за мен:

@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);
}
person LuckyMalaka    schedule 02.03.2013

В момента използвам следното решение в моя клас, разширяващо ListFragment:

1) Вие, във вашия клас onActivityCreated проверявате дали вашият адаптер (който е променлива на класа) е нула, след което го инстанцирайте. След това надуйте долния колонтитул, например така:

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

Трябва да направите това само веднъж! FooterView и адаптерът трябва да бъдат създадени само веднъж. Създавам и двете в моя onActivityCreated

Сега към „трудната част“, ​​задайте вашия фрагмент във вашия onCreate така:

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

Обичам да го правя в onCreate, защото не е подходящо за дейността. Сега с setRetainInstance(true) вашият фрагмент няма да бъде пресъздаден, след като дейността бъде унищожена, събитие като ориентация на екрана.

Сега след тези редове добавете долния колонтитул по този начин:

getListView().addFooterView(footerView);

След това свържете адаптера към списъка:

setListAdapter(adapter);

Това трябва да се прави всеки път, когато дейността умре, направете това в onActivityCreated.

И едно от другите важни неща, за които обикновено трябва да мислите, когато става дума за фрагменти, е, че не създавате фрагмента всеки път, когато се извика onCreate на дейността.

Например направете това (ако НЕ използвате пакета за поддръжка):

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

Това ще създаде фрагмента само веднъж, ако етикетът е уникален за този фрагмент, разбира се.

person Johan S    schedule 15.02.2013
comment
Не трябва да бъдете принуждавани да setRetainInstance(true). Това е агностик на въпроса. - person saiyancoder; 19.03.2014

Имах някои проблеми с височината на оформлението на заглавката, така че последвах това решение:

@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 е екземпляр на View, а DiarioAdapter е персонализиран ArrayAdapter.

АКТУАЛИЗАЦИЯ 1

Ако имате проблеми с дублиращи се фрагменти от списък, просто променете FragmentTransaction ADD за REPLACE.

person Beto Caldas    schedule 17.04.2015