Элемент ListView не останется "выбранным"
Я хочу изменить фон элемента списка, когда пользователь щелкает по нему. Вроде как страница настроек Honeycomb (хотя я не имею дело только с настройками, поэтому я не использую PreferenceActivity), у меня эта функция работает через селектор состояния селектора состояния ресурса, за исключением случаев, когда нажатие на меню просмотра списка изменяет линейное макет справа от списка (вид разделенного экрана). Я предполагаю, что просмотр списка теряет фокус, поэтому state_pressed больше не соответствует действительности.
<item android:state_pressed="true">
<shape >
<solid android:color="@color/blue1" />
</shape>
</item>
Любые советы, чтобы сохранить этот элемент списка, пока не будет выбран другой элемент списка? Спасибо!
РЕДАКТИРОВАТЬ:
Мне удалось изменить фон в setOnItemClickListener с
view.setBackgroundResource(R.color.red);
Мне нужен только один выбранный одновременно, поэтому, когда щелкнули другие элементы списка, я попытался lv.invalidate()
а также lv.getChildAt(0).invalidate()
но ни одна из них не сработала, а вторая вызывает исключение нулевого указателя. Есть идеи, как вернуть цвет?
10 ответов
Когда вы отпускаете палец из ячейки, он больше не регистрируется как нажатый. То, что вы хотите сделать, это на самом деле изменить фон отдельной строки, когда пользователь выбирает это. Это означает реализацию onItemClick или onItemTouch и пометить адаптер, чтобы перерисовать строку с новым фоном. Если вы уже используете настраиваемый адаптер списка, вы можете просто реализовать проверку на логическое значение в вашем методе getView(). Вам также нужно будет отслеживать, какие строки "выбраны", а какие нет.
псевдокод:
public View getView(int pos, View convertView, ViewGroup parent) {
if(isChecked[pos]) //set background to checked color
}
Надеюсь, это поможет,
1.- Создайте файл формы для сфокусированного элемента: \ drawable \ list_selector_focused.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient android:angle="90" android:startColor="#f5c98c" android:endColor="#f7ddb8"/>
</shape>
2.- Создайте файл формы для нажатого элемента: \ drawable \ list_selector_pressed.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient android:angle="90" android:startColor="#fb9d23" android:endColor="#ffc579" />
</shape>
3.- Создайте файл селектора списка: \ drawable \ list_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/list_selector_pressed" />
<item android:state_focused="true" android:drawable="@drawable/list_selector_focused" />
<item android:drawable="@drawable/list_selector_focused" />
</selector>
4.- Добавьте этот атрибут в свой ListView в файле макета:
android:choiceMode="singleChoice"
android:listSelector="@drawable/list_selector"
Вы можете использовать цвета вместо градиентных фигур,
Это реализация идеи sgarman:
package com.mypackage;
import java.util.Vector;
import com.myapp.R;
import com.myapp.data.Address;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class AddressesListAdapter extends BaseAdapter{
protected Context context;
protected LayoutInflater mInflater;
protected int itemResourceId;
protected Vector<Address> contentItems = new Vector<Address>();
protected Vector<Boolean> selectedStates;
private static final String TAG = "myapp";
public AddressesListAdapter(Context context, Vector<Address> contentItems) {
this.context = context;
this.contentItems = contentItems;
mInflater = LayoutInflater.from(context);
itemResourceId = R.layout.address_list_item;
selectedStates = new Vector<Boolean>();
//initial fill
clearSelectedState();
}
@Override
public int getCount() {
return contentItems.size();
}
@Override
public Object getItem(int position) {
return contentItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(itemResourceId, null);
holder = new ViewHolder();
holder.addressName = (TextView) convertView.findViewById(R.id.addressName);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Address address = (Address) contentItems.get(position);
holder.addressName.setText(address.getAddressName());
holder.addressName.setOnClickListener(new SetFocusListener(position));
//restore saved position from saving vector
if (selectedStates.get(position)) holder.addressName.setBackgroundColor(Color.BLUE);
else holder.addressName.setBackgroundColor(Color.TRANSPARENT);
return convertView;
}
private void clearSelectedState () {
selectedStates.clear();
for (int i = 0 ; i <= contentItems.size(); i++) {
selectedStates.add(new Boolean(false));
}
}
private class SetFocusListener implements View.OnClickListener {
private int position;
public SetFocusListener(int position) {
this.position = position;
}
@Override
public void onClick(View v) {
//clear selected state vector
clearSelectedState();
//set selected position
selectedStates.set(position, new Boolean(true));
//refresh adapter to redraw focus
notifyDataSetChanged();
}
}
static class ViewHolder {
TextView addressName;
}
}
Единственное, что беспокоит, это может быть дорогостоящим, чтобы установить новый слушатель для каждой итерации getView()
Проверенное состояние андроида лучше всего использовать для решения этой проблемы.
Кто-то упомянул использование android:background="? Android:attr/activBackgroundIndicator".
Это просто указывает на один из ресурсов activ_background_* в frameworks/base/core/res/res/drawable исходного кода Android. Например, activ_background_holo_dark.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="@android:drawable/list_activated_holo" />
<item android:drawable="@color/transparent" />
</selector>
По сути, вы хотите использовать state_activation для представления, когда пользователь также нажимает кнопку, когда она находится в проверенном (т.е. в постоянном выбранном состоянии) состоянии. Обратите внимание, что активация была введена только после Honeycomb, если вы нацеливаетесь на более старые устройства, вам нужно полагаться на state_checked (подробнее здесь).
Теперь, если вы хотите установить пункт как проверенный, вам нужно позвонить listView.setItemChecked(position, true)
, Вы, вероятно, захотите установить android:choiceMode
свойство в вашем ListView с соответствующим значением (например, если вы хотите, чтобы только одна вещь была выбрана одновременно, используйте singleChoice
). Вам не нужно аннулировать, вызов setItemChecked вызовет ретрансляцию, которая обновит представление.
Также будьте осторожны, если вы разрешаете переупорядочивать элементы в вашем ListView, так как текущий проверенный элемент (ы) нужно будет обновить. Если вы используете стабильные идентификаторы, это будет выполнено автоматически.
Чтобы увидеть пример этого в действии, ознакомьтесь с примером кода NavigationDrawer, который можно найти в обучающей серии: http://developer.android.com/training/implementing-navigation/nav-drawer.html.
По умолчанию "Выбрано" - это не то же самое, что "Нажатие", когда вы используете сенсорный интерфейс - что вызывает у меня настоящую головную боль, когда я начинаю разработку для Android.
Чтобы поддерживать как пользователей, которые перемещаются на ощупь, так и пользователей, которые используют колеса прокрутки / трекболы, вы можете использовать setSelection и выполнять свои манипуляции в реализации AdapterView.OnItemSelectedListener (устанавливается с помощью setOnItemSelectedListener).
Другой недостаток заключается в том, что setSelection не будет выделять элемент, если последнее событие было сенсорным.
Я бы порекомендовал вам создать собственный вид для элементов списка и обработать выделение там.
Надеюсь это поможет,
Фил Лелло
Я использовал android:state_activated="true"
вместо state_selected
, Отлично работает!
Если вы сохраняете свой listView на протяжении всей деятельности, вы можете сделать mListView.isItemChecked(position)
в getView()
метод. И они устанавливают цвет фона в зависимости от результата.
Итак, я попробовал решение выше, где оно говорит:"Это реализация идеи sgarman:" Это работает, только если SetFocusListener является OnTouchListner. В остальном метод onClick потребляет клик. Мне пришлось соединить это решение с прослушивателем OnItemClick в моем элементе списка, чтобы в списке отображался выделенный элемент.
Пытаться
android:background="?android:attr/activatedBackgroundIndicator"
;)