Android: Не знаете, почему мой просмотр списка перепутан?
Я реализовал ListView, который работал правильно, пока я не добавил более 5 элементов и 2 заголовков. Я не совсем уверен, почему некоторые предметы не появляются, а другие появляются несколько раз. Любая помощь в исправлении этого будет высоко ценится. Код включен ниже.
Toolbox.java
public class Toolbox extends Fragment {
private ListView lstView;
private View rootView;
List<Tools> tools;
public static Toolbox newInstance(Context context) {
Toolbox fragment = new Toolbox();
return fragment;
}
public Toolbox() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
((MainActivity) getActivity()).setActionBarTitle("Technical Toolbox");
rootView = inflater.inflate(R.layout.fragment_toolbox, container, false);
lstView =(ListView) rootView.findViewById(R.id.list);
final FragmentActivity c = getActivity();
//final RecyclerView recyclerView = (RecyclerView) recView.findViewById(R.id.reView);
setToolBoxData();
setToolBoxAdapter();
return rootView;
}
private void setToolBoxAdapter() {
ListArrayAdapter adapter = new ListArrayAdapter(getActivity(),tools);
lstView.setAdapter(adapter);
}
private void setToolBoxData(){
tools=new ArrayList<>();
tools.add(new Header("Languages"));
tools.add(new ListItem("Android",R.drawable.ic_android));
tools.add(new ListItem("XML", R.drawable.ic_xml));
tools.add(new ListItem("Java",R.drawable.ic_java));
tools.add(new ListItem("JavaScript", R.drawable.ic_javascript));
tools.add(new ListItem("C++", R.drawable.ic_cpp));
tools.add(new ListItem("Visual Basic", R.drawable.ic_vb));
tools.add(new ListItem("HTML", R.drawable.ic_html));
tools.add(new ListItem("CSS", R.drawable.ic_css));
tools.add(new Header("Source Control"));
tools.add(new ListItem("Git", R.drawable.ic_git));
tools.add(new ListItem("GitHub", R.drawable.ic_github_cat));
tools.add(new ListItem("SourceTree", R.drawable.ic_sourcetree));
tools.add(new ListItem("BitBucket", R.drawable.ic_bitbucket));
tools.add(new Header("DataBase"));
tools.add(new ListItem("Parse", R.drawable.ic_parse));
tools.add(new ListItem("MS Access", R.drawable.ic_access));
tools.add(new ListItem("SQL", R.drawable.ic_sql));
tools.add(new Header("Design & IDE Tools"));
tools.add(new ListItem("Android Studio", R.drawable.ic_androidstudio));
tools.add(new ListItem("Visual Studio", R.drawable.ic_visual_studio));
tools.add(new ListItem("Genymotion", R.drawable.ic_genymotion));
tools.add(new ListItem("Ionic", R.drawable.ic_ionic));
tools.add(new Header("Office Tools"));
tools.add(new ListItem("MS Project", R.drawable.ic_project));
tools.add(new ListItem("MS Visio", R.drawable.ic_visio));
tools.add(new ListItem("MS Excel", R.drawable.ic_excel));
tools.add(new ListItem("MS Word", R.drawable.ic_word));
}
}
ListArrayAdapter.java
public class ListArrayAdapter extends ArrayAdapter<Tools> {
private LayoutInflater mInflater;
public enum RowType{ LIST_ITEM, HEADER_ITEM }
public ListArrayAdapter(Context context, List<Tools> tools){
super(context, 0, tools);
mInflater = LayoutInflater.from(context);
}
@Override
public int getViewTypeCount(){return RowType.values().length;}
@Override
public int getItemViewType(int pos){return getItem(pos).getViewType();}
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int rowType = getItemViewType(position);
View View;
if (convertView == null) {
holder = new ViewHolder();
switch (rowType) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.listview_item, null);
holder.View=getItem(position).getView(mInflater, convertView);
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.list_title, null);
holder.View=getItem(position).getView(mInflater, convertView);
break;
}
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
public static class ViewHolder {
public View View;
}
}
Tools.java
public interface Tools {
public int getViewType();
public View getView(LayoutInflater inflater, View convertView);
}
ListItem.java
public class ListItem implements Tools {
private final String str1;
private final int pic1;
public ListItem(String text1, int pic1) {
this.str1 = text1;
this.pic1 = pic1;
}
@Override
public int getViewType() {
return ListArrayAdapter.RowType.LIST_ITEM.ordinal();
}
@Override
public View getView(LayoutInflater inflater, View convertView) {
View view;
if (convertView == null) {
view = (View) inflater.inflate(R.layout.listview_item, null);
// Do some initialization
} else {
view = convertView;
}
TextView text1 = (TextView) view.findViewById(R.id.listText);
ImageView picture1 = (ImageView) view.findViewById(R.id.listIcon);
text1.setText(str1);
picture1.setImageResource(pic1);
return view;
}
}
Header.java
public class Header implements Tools {
private final String name;
public Header(String name) {
this.name = name;
}
@Override
public int getViewType() {
return ListArrayAdapter.RowType.HEADER_ITEM.ordinal();
}
@Override
public View getView(LayoutInflater inflater, View convertView) {
View view;
if (convertView == null) {
view = (View) inflater.inflate(R.layout.header, null);
// Do some initialization
} else {
view = convertView;
}
TextView text = (TextView) view.findViewById(R.id.separator);
text.setText(name);
return view;
}
}
3 ответа
Вы только заполняете свои виджеты строк в if (convertView == null)
дело. Если convertView
не является null
, вы просто возвращаете его без изменений, то есть у него будут данные position
, не position
это запрашивается.
IOW, вам нужно вызывать такие методы, как setText()
а также setImageResource()
на каждом getView()
вызов, чтобы заполнить виджеты строки данными для запрошенного position
,
Краткая предыстория:
На самом деле сегодня я столкнулся с этой же ошибкой. Как описано, я также сделал 90-95% идентичную реализацию. Однако я также видел принятый ответ в этой теме вопросов и ответов. Но я не могу с тобой согласиться! Поэтому я искал и искал, почему мой проще ArrayAdapter
реализация не работает должным образом. В первый раз он загружается хорошо. Но вскоре после того, как я прокручиваю это однажды? Все типы строк перемешаны!
Обобщенный ответ:
Прочитайте Документ разработчика Android для получения дополнительной информации, которую вы могли бы найти ключ непосредственно. Для реализации нескольких типов Views
за ListView
Строки мы должны по существу реализовать, getItemViewType()
а также getViewTypeCount()
методы. А также getItemViewType()
Документация дает нам Примечание следующим образом:
Примечание: целые числа должны быть в диапазоне
0
вgetViewTypeCount() - 1
,IGNORE_ITEM_VIEW_TYPE
также могут быть возвращены.
Так в вашем getItemViewType()
Вы должны вернуть значения для Типа представления, начиная с 0, до последнего типа как (количество типов - 1). Например, допустим, у вас есть только два типа представлений? Таким образом, в зависимости от объекта данных для представления, вы можете вернуть только 0 или 1 в getItemViewType()
метод.
Если вы не получили подсказку или все еще не можете решить и нуждаетесь в дополнительной информации, пожалуйста, прочтите ее ниже:
Детальное объяснение:
Согласно Документации разработчика Android или Документу API, упоминалось, что для реализации нескольких типов представлений в
ListView
Адаптер, мы должны реализовать следующие методы:
public int getItemViewType (int position)
public int getViewTypeCount ()
И из вышеупомянутых двух методов,
getItemViewType
важно в нашем случае (где у нас есть несколько типов представлений). Это правда, верно? И что?Вот где я и @8BitYoda ошиблись. Неправильная вещь ОП была в том, что он определил
Enum
где это не дает типы как диапазонintegers
в диапазоне от 0 до(getViewTypeCount() - 1)
,
И что я сделал, я определил типы следующим образом:
private static final int TYPE_ITEM = 1;
private static final int TYPE_ITEM = 2;
И сначала я не реализовал, getViewTypeCount()
, поэтому я реализовал это следующим образом:
public int getViewTypeCount() {
return 2;
}
Затем, вскоре после того, как я запустил приложение и попытался загрузить это представление с помощью ListView, оно дало сбой, выдав мне следующее исключение:
java.lang.ArrayIndexOutOfBoundsException: length = 2; index = 2 в android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:6643) в android.widget.ListView.measureHeightOfChildren(ListView.java:1292) в android.widget.ListView.onMeasure(ListView.java:11):
:
:
на com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Чего-чего?:O
Это косвенно говорит, что это связано с целым числом, которое я возвращаю из метода getViewTypeCount()
, поскольку я возвращаю 2. И я возвращаю 2, потому что у меня есть только два типа. Поэтому я вернулся к документации Android, чтобы получить окончательную помощь. И это действительно помогло мне и решило мой вопрос, прочитав документ, касающийся методов, которые я реализовал.
Для быстрого взгляда посмотрите на изображение ниже:
С крошечным маленьким шрифтом он дал нам ЗАМЕТКУ.
Что примечание getItemViewType (int position)
метод говорит?
Примечание: целые числа должны быть в диапазоне
0
вgetViewTypeCount() - 1
,IGNORE_ITEM_VIEW_TYPE
также могут быть возвращены.
Поэтому сразу после этого я понял, что мне нужно переназначить type integers
Я отправляю в начало от 0 до любого количества типов, таких как индекс массива с нуля. Так что я исправил эти две строки, и потом это сработало!
private static final int TYPE_ITEM = 0;
private static final int TYPE_ITEM = 1;
Извините, я знаю, что мой ответ прошел немного дольше, чем я ожидал, почти как мини-учебник. Но это нормально для меня, я потратил около часа, чтобы написать это, потому что я бы потратил около 5 часов, чтобы понять эту глупую ошибку. Кто думает, что типы должны назначаться, начиная с 0, как индекс массива на основе 0?
Поэтому я надеюсь, что мой ответ может быть полезен кому-то для решения этой ошибки.
Ура!!!
Вместо того, чтобы использовать позиции, вы должны использовать некоторую форму идентификатора для уникальности.
Также, поскольку представления перерабатываются, вам необходимо обновить их новыми данными.
if (convertView == null) {
holder = new ViewHolder();
switch (rowType) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.listview_item, null);
holder.View=getItem(position).getView(mInflater, convertView);
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.list_title, null);
holder.View=getItem(position).getView(mInflater, convertView);
break;
}
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
//here update the holder in else case also.
}
return convertView;