Лучшее место для addHeaderView в ListFragment
У меня возникли проблемы с настройкой моего настраиваемого заголовка в моем списке.
Я создаю ListFragment с пользовательским адаптером. У меня список работает нормально, но я пытаюсь выяснить, где в жизненном цикле фрагмента, чтобы прикрепить заголовок.
Я знаю, что заголовок должен быть добавлен до того, как вы установите адаптер.
Я попытался добавить свой заголовок в onActivityCreated, но он вызывается каждый раз, когда мой Фрагмент возвращается из задней части, и поскольку я также устанавливаю свой адаптер в onActivityCreated, он терпит неудачу.
Я попытался добавить его в onCreate, но иерархия представления недоступна на этом этапе жизненного цикла.
Я попробовал добавить его в onCreateView, но я не смог отбросить представление, полученное из inflate, в ListView. Поэтому я не мог добавить свой заголовок в вид ванили.
Любые мысли?
Ответы
Ответ 1
Я не знаю, решила ли вы свою проблему, но вот решение, которое сработало для меня:
Не вызывайте ListFragment.setListAdapter()
в ListFragment.onCreate()
. Убедитесь, что у вас есть переменная поля, которая может содержать заголовок, возможно, например:
View mheaderView;
Затем в вашем ListFragment.onCreateView()
раздуйте заголовок View и назначьте его своей переменной следующим образом:
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);
Ответ 2
Это решение работает с переключением экрана:
В onActivityCreated():
getListView().addHeaderView(mHeaderView);
if (mMyAdapter == null) {
mMyAdapter = new MyAdapter(getActivity(), null);
}
setListAdapter(mMyAdapter);
И в onDestroyView()
setListAdapter(null);
Ответ 3
Мое решение:
public void onActivityCreated(Bundle savedInstanceState) {
setListAdapter(null);
getListView().addHeaderView(mHeader);
setListAdapter(mAdapter);
}
Ответ 4
Это мое решение для обработки нижнего колонтитула/заголовка в виде списка. Я использую его в сохраненном фрагменте. Адаптер инициализируется в методе 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);
}
Ответ 5
Как короткое решение, которое сработало для меня:
@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);
}
Ответ 6
В настоящее время я использую следующее решение в своем классе, расширяющее ListFragment
:
1) Вы в своем классе onActivityCreated
проверяете, является ли ваш адаптер (который является переменной класса) равным null, а затем создайте его. Затем раздуйте нижний колонтитул, например, следующим образом:
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
.
Например, сделайте это (если ваш НЕ с помощью supportpackage):
MyFragment myFragment = (MyFragment)
getFragmentManager().findFragmentByTag(tag);
if (myFragment == null) {
myFragment = MyFragment.newInstance();
getFragmentManager().beginTransaction().
add(myFragment, tag).commit();
}
Это создаст только один фрагмент, если тег уникален для этого фрагмента.
Ответ 7
У меня возникли проблемы с высотой макета заголовка, поэтому я выполнил это решение:
@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));
}
Заголовок - это экземпляр View и DiarioAdapter - это настраиваемый ArrayAdapter.
ОБНОВЛЕНИЕ 1
Если у вас есть проблемы с дублирующимся списком, просто измените FragmentTransaction ADD для REPLACE.