Элемент 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"

;)

Ты пытался android:state_selected="true"?

Другие вопросы по тегам