ListView остается выбранным? - PullRequest
10 голосов
/ 24 июня 2010

У меня есть представление списка, полное элементов, после того, как пользователи выбирают элемент, он загорается, и затем он возвращается к нормальному состоянию.Есть ли способ сделать так, чтобы при выборе пользователем элемента в моем ListView он оставался выделенным и выделенным?

Ответы [ 7 ]

15 голосов
/ 16 июня 2012

По-видимому, "исчезающий выбор" - это дизайн; это то, что называется " сенсорный режим ". Я прочитал этот документ и до сих пор понятия не имею, почему они думают, что это хорошая идея. Я предполагаю, что, поскольку Android изначально был разработан для устройств с небольшим экраном, они ожидали, что вы заполните экран списком, а затем, когда пользователь щелкнет элемент, перейдете к новому списку на другом экране. Таким образом, пользователь не будет знать, что Android потерял отслеживание выбранного элемента.

Но это поведение весьма раздражает, если, например, вы хотите, чтобы пользователь выбрал элемент, а затем отобразил информацию об этом элементе на том же экране. Если выбор исчезает, как пользователь должен знать, что он нажал (при условии, конечно, что у пользователя есть степень внимания золотой рыбки)?

Одним из возможных решений является изменение всех элементов списка на переключатели. Мне не очень нравится это решение, потому что оно тратит впустую экранную недвижимость. Я бы предпочел просто использовать цвет фона, чтобы показать, какой элемент выбран. До сих пор я видел одно решение, но оно не совсем полное или общее. Итак, вот мое решение:

1. В вашем XML-файле макета

Перейдите к элементу ListView и следующему атрибуту: android:choiceMode="singleChoice". Я не совсем уверен, что это делает (само по себе это не позволяет пользователю выбирать что-либо), но без этого атрибута приведенный ниже код не работает.

2. Определите следующий класс

Он используется для отслеживания выбранного элемента, а также позволяет имитировать передачу по ссылке в Java:

public class IntHolder {
    public int value;
    public IntHolder() {}
    public IntHolder(int v) { value = v; } 
}

3. Поместите следующий код куда-нибудь

Полагаю, вы поместили это в свое задание, но на самом деле оно может пойти в любой класс:

static void setListItems(Context context, AdapterView listView, List listItems, final IntHolder selectedPosition)
{
    setListItems(context, listView, listItems, selectedPosition, 
                 android.R.layout.simple_list_item_1, 
                 android.R.layout.simple_spinner_dropdown_item);
}
static void setListItems(Context context, AdapterView listView, List listItems, final IntHolder selectedPosition, 
                         int list_item_id, int dropdown_id)
{
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> list, View lv, int position, long id) {
            selectedPosition.value = position;
        }
    });
    ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context, list_item_id, listItems) { 
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View itemView = super.getView(position, convertView, parent);
            if (selectedPosition.value == position)
                itemView.setBackgroundColor(0xA0FF8000); // orange
            else
                itemView.setBackgroundColor(Color.TRANSPARENT);
            return itemView;
        }
    };
    adapter.setDropDownViewResource(dropdown_id);
    listView.setAdapter(adapter);
}

Этот код выполняет две функции: он присоединяет элементы списка (например, List<String>) к вашему ListView и переопределяет ArrayAdapter.getView() с помощью некоторого кода, который изменяет фон выбранного элемента.

4. Используйте этот код для настройки вашего списка

Например:

ListView _list;
IntHolder _selectedItem = new IntHolder(-1); // nothing selected at first

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    _list = (ListView)findViewById(R.id.list);
    List<String> items = Arrays.asList("Item 1", "Item 2", "Item 3");
    setListItems(this, _list, items, _selectedItem);
}

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

Предупреждение : это решение нуждается в дальнейшей разработке. Если пользователь использует клавиши со стрелками или кнопки для выбора элемента, этот элемент будет , а не , с точки зрения IntHolder. Если пользователь нажимает кнопку без метки (как называется эта кнопка? «Ввод»?), Тогда элемент станет «официально» выбранным, но тогда у вас будет другая проблема, потому что, если пользователь снова использует клавиши со стрелками, он будет выглядеть вроде два предмета выбраны. Оставьте комментарий, если вы поймете, как синхронизировать «внутренний выбор» в IntHolder с «выбором клавиатуры» или как там это называется. Во всяком случае, как это называется ?

2 голосов
/ 21 февраля 2014

Здесь более простое решение, чем у Qwertie's:

Не полагайтесь на данный механизм выбора. Сделай сам.

View mSelectedItemView = null; //class member variable
View mTouchedItemView = null; //class member variable

ListView v = (ListView) getActivity().findViewById(R.id.listView);
// select on click
v.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> adapter,
            View clickedViewItem, int position, long id) {
        if (mSelectedItemView != null)
            selectedItemView.setBackgroundColor(Color.WHITE);
        clickedViewItem.setBackgroundColor(Color.YELLOW);
        mSelectedItemView = clickedViewItem;
    }
});
// highlight on touch
v.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (v instanceof ListView) {
            ListView listView = (ListView) v;
            // Find the child view that was touched (perform a
            // hit test)
            Rect rect = new Rect();
            int childCount = listView.getChildCount();
            int[] listViewCoords = new int[2];
            v.getLocationOnScreen(listViewCoords);
            int x = (int) event.getRawX() - listViewCoords[0];
            int y = (int) event.getRawY() - listViewCoords[1];
            View child;
            for (int i = 0; i < childCount; i++) {
                child = listView.getChildAt(i);
                child.getHitRect(rect);
                if (rect.contains(x, y)) {
                    View touchedView = child;
                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
                        touchedView
                                .setBackgroundColor(Color.RED);
                        mTouchedItemView = touchedView;
                    } else if (event.getAction() == MotionEvent.ACTION_UP) {
                        mTouchedItemView 
                                .setBackgroundColor(Color.WHITE);
                    }
                }
            }
        }
        return false;
    }
});

Также этот метод имеет дело только с кликами и не будет работать, если пользователь использует клавиши со стрелками.

Отказ от ответственности: снятие подсветки после касания не работает надежно.

Кредиты для касающейся части идут на ozik.dev: Получить элемент из ListView только с OnTouchListener

2 голосов
/ 03 сентября 2013

В ListView есть атрибут listSelector:

Drawable используется для обозначения текущего выбранного элемента в списке.

http://developer.android.com/reference/android/widget/AbsListView.html#attr_android:listSelector


РЕДАКТИРОВАТЬ после Stan комментарий

Чтобы гарантировать, что ListView остается выбранным, вы должны

① Установите атрибут представления choiceMode через xml или программно.

② Используйте адаптер, использующий представления, которые реализуют интерфейс Checkable, например CheckedTextView (внутри simple_list_item_single_choice макет).

Файл TestActivity.java

public class TestActivity extends Activity {

    private static final int SINGLE_CHOICE = android.R.layout.simple_list_item_single_choice;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);

        String[] items = {"test 1", "test 2", "test 3"};
        ListAdapter adapter = new ArrayAdapter<String>(this, SINGLE_CHOICE, items);
        ListView list = (ListView) findViewById(R.id.testList);
        list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        list.setAdapter(adapter);
    }
}
0 голосов
/ 20 июня 2017

Просто добавьте это в свой ListView:

android:listSelector="@color/my_color"
0 голосов
/ 28 февраля 2016

Используйте файл Selector.XML и этот код:

    //SetOnClickListner to catch Events
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         view.setSelected(true);
        }
    });
0 голосов
/ 31 декабря 2014

просто добавьте это в свой макет списка

 android:listSelector="@drawable/selector_expandable_listview" 
 android:drawSelectorOnTop="true"
0 голосов
/ 27 сентября 2013

Этот ответ работает, попробуйте этот

@Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long arg3)
    {
        for(int a = 0; a < parent.getChildCount(); a++)
        {
            parent.getChildAt(a).setBackgroundColor(Color.TRANSPARENT);
        }
    view.setBackgroundColor(Color.GREEN);
}
...