ListView с ArrayAdapter и ViewHolder добавляет значки к неправильному элементу
У меня есть динамический ListView
, который использует ArrayAdapter
. Когда имя выбрано из счетчика, имя вместе со значком, показывающим, являются ли они мужчиной или женщиной, добавляется к ListView
.
В основном все хорошо (имя добавляется в список правильно, вместе со значком). Но значок, показывающий пол, добавляется к неправильному элементу в ListView
. Имя добавляется в нижнюю часть списка, но значок помещается в имя вверху списка. Я не знаю, так ли это, как я использую ViewHolder
, но на нем есть нулевая документация в веб-сайте Android.
// Listview inflater
inflater = (LayoutInflater) (this).getSystemService(LAYOUT_INFLATER_SERVICE);
// List Array.
mAdapter = new ArrayAdapter<String>(this, R.layout.player_simple_list,
R.id.label, mStrings) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.i("ANDY","View getView Called");
// A ViewHolder keeps references to children views to
// avoid unneccessary calls to findViewById() on each row.
ViewHolder holder;
if (null == convertView) {
Log.i("ANDY","Position not previously used, so inflating");
convertView = inflater.inflate(R.layout.player_simple_list, null);
// Creates a ViewHolder and store references to the
// two children views we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.label);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
if (sexmale == true) {
holder.icon.setImageBitmap(maleicon);
}
else {
holder.icon.setImageBitmap(femaleicon);
}
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind the data efficiently with the holder.
holder.text.setText(getItem(position));
// Change icon depending is the sexmale variable is true or false.
Log.i("ANDY","getCount = "+mAdapter.getCount());
return convertView;
}
};
setListAdapter(mAdapter);
Ответы
Ответ 1
Обновление: ViewHolder
предназначен только для хранения ссылок на представления компонентов внутри макета элемента. Это помогает избежать накладных расходов при вызове findViewById
для рендеринга каждого компонента внутри сложных макетов элементов с несколькими компонентами (например, TextView
и ImageView
в этом случае).
Я исправил его с помощью подпрограммы (называемой getSex
) для получения данных о сексе и установки всех данных вида, включая значки вне блоков if-else
.
Рабочий код теперь выглядит следующим образом:
if (null == convertView) {
Log.i("ANDY","Position not previously used, so inflating");
convertView = inflater.inflate(R.layout.player_simple_list, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.label);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind the data efficiently with the holder.
holder.text.setText(getItem(position));
// Change icon depending is the sexmale variable is true or false.
if (getSex (getItem(position)) == true) {
holder.icon.setImageBitmap(maleicon);
}
else {
holder.icon.setImageBitmap(femaleicon);
}
return convertView;
Ответ 2
Вы должны установить значки после if-else-if
для создания или привязки holder
. В противном случае значки будут правильно отображаться только в первых нескольких элементах в списке i.e, пока ListView
не будет заполнен.
public View getView(int position, View convertView, ViewGroup parent) {
Log.i("ANDY","View getView Called");
// A ViewHolder keeps references to children views
// to avoid unneccessary calls to findViewById() on each row.
ViewHolder holder;
if (null == convertView) {
Log.i("ANDY","Position not previously used, so inflating");
convertView = inflater.inflate(R.layout.player_simple_list, null);
// Creates a ViewHolder and store references to
// the two children views we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.label);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind the data efficiently with the holder.
holder.text.setText(getItem(position));
// Change icon depending is the sexmale variable is true or false.
if (sexmale == true) {
holder.icon.setImageBitmap(maleicon);
}
else {
holder.icon.setImageBitmap(femaleicon);
}
Log.i("ANDY","getCount = "+mAdapter.getCount());
return convertView;
}
Ответ 3
Вам следует перейти от нескольких строк данных после комментария, как в этом вопросе
// Bind the data efficiently with the holder.
чтобы он выглядел следующим образом:
if (null == convertView) {
Log.i("ANDY","Position not previously used, so inflating");
convertView = inflater.inflate(R.layout.player_simple_list, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind the data efficiently with the holder.
holder.text = (TextView) convertView.findViewById(R.id.label);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
if (sexmale == true) {
holder.icon.setImageBitmap(maleicon);
}
else {
holder.icon.setImageBitmap(femaleicon);
}
holder.text.setText(getItem(position));