Элемент ListView не останется «выбранным» - PullRequest
8 голосов
/ 16 апреля 2011

Я хочу изменить фон элемента списка, когда пользователь щелкает по нему. Вроде как страница настроек сота (хотя я не имею в виду только настройки, поэтому я не использую PreferenceActivity), у меня эта функция работает через селектор состояния селектора состояния ресурса, за исключением случаев, когда нажимают на Меню просмотра списка изменяет линейный макет справа от просмотра списка (вид разделенного экрана). Я предполагаю, что просмотр списка теряет фокус, поэтому state_pressed больше не имеет значения.

   <item android:state_pressed="true">
     <shape  >
        <solid android:color="@color/blue1" />
     </shape>
   </item>

Какие-либо советы, чтобы сохранить цвет этого элемента списка до тех пор, пока не будет выбран другой элемент списка? Спасибо!

EDIT:

Мне удалось изменить фон в setOnItemClickListener с помощью

view.setBackgroundResource(R.color.red); 

Мне нужен только один выбранный одновременно, поэтому, когда щелкают другие элементы списка, я пробовал lv.invalidate() и lv.getChildAt(0).invalidate(), но ни одна из них не работала, а вторая вызывает исключение нулевого указателя. Есть идеи, как вернуть цвет?

Ответы [ 10 ]

9 голосов
/ 16 апреля 2011

Когда вы отпускаете палец из ячейки, он больше не регистрируется при нажатии. То, что вы хотите сделать, это на самом деле изменить фон отдельной строки, когда пользователь выбирает это. Это означает реализацию onItemClick или onItemTouch и пометку адаптера для перерисовки строки с новым фоном. Если вы уже используете настраиваемый адаптер списка, вы можете просто выполнить проверку на логическое значение в вашем методе getView (). Вам также нужно будет отслеживать, какие строки «выбраны», а какие нет.

псевдокод:

   public View getView(int pos, View convertView, ViewGroup parent) {
      if(isChecked[pos]) //set background to checked color
   }
5 голосов
/ 18 марта 2013

Надеюсь, эта справка,

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 в макетеfile:

 android:choiceMode="singleChoice"
 android:listSelector="@drawable/list_selector"

Вы можете использовать цвета вместо градиентных фигур,

3 голосов
/ 31 августа 2013

Проверенное состояние андроида лучше всего использовать для решения этой проблемы.

Кто-то упоминал об использовании 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.

3 голосов
/ 23 сентября 2011

Это реализация идеи 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 ()

2 голосов
/ 16 апреля 2011

По умолчанию «Выбрано» не то же самое, что «Нажатие», когда вы используете сенсорный интерфейс - что вызывает у меня настоящую головную боль, когда я начинаю разработку для Android.

Для поддержки обоих пользователейкоторые перемещаются на ощупь и пользователей, которые используют колеса прокрутки / трекболы, вы можете использовать setSelection и выполнять свои манипуляции в реализации AdapterView.OnItemSelectedListener (устанавливается с помощью setOnItemSelectedListener ).

Другой недостаток заключается в том, что setSelection не будет выделять элемент, если последнее событие было событием касания.

Я бы порекомендовал вам создать пользовательскийПросматривайте элементы списка и обрабатывайте выделение там.

Надеюсь, это поможет,

Фил Лелло

0 голосов
/ 27 февраля 2015

Если вы сохраняете свой listView на протяжении всего действия, вы можете сделать mListView.isItemChecked(position) в методе getView(). И они устанавливают цвет фона в зависимости от результата.

0 голосов
/ 20 января 2015

Я использовал android:state_activated="true" вместо state_selected.Это работает как шарм!

0 голосов
/ 18 октября 2014

Хорошо, поэтому я попробовал решение выше, где оно говорит: «Это реализация идеи sgarman:« Это работает, только если SetFocusListener является OnTouchListner. В остальном метод onClick потребляет клик. Мне пришлось соединить это решение с прослушивателем OnItemClick в моем элементе списка, чтобы в списке отображался выделенный элемент.

0 голосов
/ 30 марта 2013

попробуй

    android:background="?android:attr/activatedBackgroundIndicator"

;)

0 голосов
/ 16 апреля 2011

Вы пробовали android:state_selected="true"?

...