Android: доступ к дочерним представлениям из ListView

Мне нужно узнать положение в пикселях одного элемента в списке, отображаемом с помощью ListView. Похоже, я должен получить один из TextView's, а затем использовать getTop(), но я не могу понять, как получить дочернее представление ListView.

Обновлять: Дочерние элементы ViewGroup не соответствуют 1 к 1 элементам в списке для ListView. Вместо этого дочерние элементы ViewGroup соответствуют только тем представлениям, которые видны прямо сейчас. Таким образом, getChildAt() работает с внутренним индексом ViewGroup и не обязательно имеет какое-либо отношение к позиции в списке, которую использует ListView.

108
0
134 549
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Быстрый поиск в документации для класса ListView обнаружил методы getChildCount () и getChildAt (), унаследованные от ViewGroup. Можете ли вы перебрать их, используя их? Я не уверен, но попробовать стоит.

Нашел здесь

Я пробовал это для выбора. Обычно это работает, но иногда возникают отдельные ошибки, и это ненадежно. Я бы не рекомендовал это.

Timmmm 18.09.2012 16:13

Спасибо, Тимммм, я на самом деле не пробовал, просто нашел в документации.

Feet 02.10.2012 05:30

Предполагается, что вы знаете позицию элемента в ListView:

  View element = listView.getListAdapter().getView(position, null, null);

Затем вы сможете вызвать getLeft () и getTop (), чтобы определить положение элементов на экране.

getView() вызывается изнутри ListView при заполнении списка. Вы не следует используете его, чтобы получить представление в этой позиции в списке, поскольку вызов getView() с нулевым значением для convertView заставляет адаптер расширять новое представление из ресурса макета адаптера (не получает представление, которое уже отображается).
Joe 21.04.2010 02:51

Равная позиция будет позицией на визуальном экране, а не позицией источника данных адаптера.

Vikas 27.07.2011 09:09

@jasonhudgins Это метод, который я использовал, потому что я подумал, что он лучший, но когда я пытаюсь сделать индикатор выполнения в дочернем представлении невидимым, но вместо этого он сделал все индикаторы выполнения в listvew невидимыми ........ все в весь принятый ответ помог

Edijae Crusar 16.02.2016 14:57
Ответ принят как подходящий

См .: Android ListView: получить индекс данных видимого элемента и в сочетании с частью ответа Feet выше, может дать вам что-то вроде:

int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
  Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
  return;
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
View wantedView = listView.getChildAt(wantedChild);

Преимущество состоит в том, что вы не перебираете дочерние элементы ListView, что может снизить производительность.

Отличный ответ, но не совсем работает, когда в вашем списке есть заголовки. Чтобы исправить это, firstPosition должен быть назначен int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();.

pospi 27.10.2011 12:13

@pospi: спасибо, хороший момент! Я обновил свой ответ, чтобы учесть это.

Joe 31.10.2011 23:20

Хороший ответ и работает в большинстве случаев, но я не понимаю, почему вы считаете, что дочерние представления появляются в том порядке, в котором они находятся в массиве дочерних представлений. Поскольку представления можно использовать повторно, как мы можем быть уверены, что первое представление не представляет собой последнее видимое представление?

Victor Denisov 28.10.2013 14:01

@VictorDenisov: это может произойти только в потоке пользовательского интерфейса; поэтому поток пользовательского интерфейса будет заблокирован во время выполнения этого кода, поэтому дочерние представления являются стационарными и не будут изменены. ListView уже обрабатывает "перемещение" дочерних представлений после перезапуска старых convertView и т.д., поэтому вам может гарантировано, что ListView.getChildAt(0)является фактически является первым прикрепленным представлением от адаптера. Оно может быть не полностью видимым (и может даже не быть видимым вообще, в зависимости от порогового значения «видимости» ListView перед повторным использованием представления, которое он считает «прокрученным вне поля зрения»).

Joe 31.10.2013 20:33

@Matheus, Android ListView работает не так. Если элемент списка находится за пределами экрана, его представление уже было переработано и повторно использовано для одного из других элементов списка, которые являются на экране. Вам следует переосмыслить то, как вы используете ListView, если это необходимо.

Joe 01.07.2015 17:55

У меня тот же вопрос, что и у Матеуса. Работая над ExpandableListView, если я что-то делаю с дочерним элементом, а groupView не отображается, я не могу изменить его представление. Адаптером не перерисовывается кстати, проверял. Я бы хотел найти решение для этого

Teo Inke 14.07.2015 19:19

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

Teo Inke 14.07.2015 20:07

В каком методе Activity или Fragment я должен использовать этот код?

Ksenia 20.10.2016 16:40

Этот код проще использовать:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if (rowView != null)
        {
           // Your code here
        }

работает не всегда. getChildAt отсчитывает от первой видимой строки, а не от начала данных.

SteelBytes 13.10.2012 09:51

Аргумент ViewID сбивает с толку. Это индекс (или позиция). Идентификатор представления - это полностью произвольное целое число, генерируемое инструментом aapt.

Johan Pelgrim 16.10.2012 15:46
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
        View v;
        int count = parent.getChildCount();
        v = parent.getChildAt(position);
        parent.requestChildFocus(v, view);
        v.setBackground(res.getDrawable(R.drawable.transparent_button));
        for (int i = 0; i < count; i++) {
            if (i != position) {
                v = parent.getChildAt(i);
                v.setBackground(res.getDrawable(R.drawable.not_clicked));
            }
        }
    }
});

По сути, создайте два Чертежи - один прозрачный, а другой желаемого цвета. Запросите фокус в выбранной позиции (int position, как определено) и измените цвет указанной строки. Затем пройдите по родительскому ListView и соответствующим образом измените все остальные строки. Это учитывает случаи, когда пользователь нажимает на listview несколько раз. Это делается с помощью индивидуального макета для каждой строки в ListView. (Очень просто, просто создайте новый файл макета с TextView - не устанавливайте фокусируемый или кликабельный!).

Специальный адаптер не требуется - используйте ArrayAdapter

getChildAt относится к текущим прокручиваемым элементам. Это перестанет работать, если вы немного прокрутите свой список.

nurettin 24.10.2016 21:44
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);

Немного проработать

innoSPG 29.01.2016 18:18

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