#android #listview #onitemclicklistener
#Android #listview #onitemclicklistener
Вопрос:
У меня есть представление списка, и в каждом элементе списка, который у меня есть для просмотра изображений и трех текстовых представлений, три из этих изображений должны действовать как кнопка изображения, т.е. Реагировать на события при нажатии, а также два текстовых представления. Я пытался использовать ItemOnClickListeneri, что означает следующее
@Override
public void onItemClick(AdapterView<?> arg0, View convertView, int pos,
long arg3) {
// TODO Auto-generated method stub
bomb = (ImageView) convertView.findViewById(R.id.bomb);
Log.i("Item Clicked", "Item was clicked at pos" position);
bomb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// Perform action on click
//Run what ever task neccessary
}
});
}
Но у этого есть проблема, она реагирует только на второй щелчок. я знаю, что это как-то связано с родительским и дочерним фокусом, но я не смог обойти это.
Я также пытался использовать
статический класс
View Holder
, за исключением того, что я неправильно понял реализацию, он вообще не реагирует даже после двух щелчков мыши.
Также я использую пользовательский адаптер, раньше я делал это непосредственно из метода getView
overide, но я обнаружил, что это не лучший способ реализовать то, что я хочу сделать.
Пожалуйста, мне нужно что-то, что сработало бы для меня, потому что я попробовал пару вещей, отличных от вышеупомянутых, но они потерпели неудачу.
Получить коды просмотра
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
pos = position;
if(convertView == null)
{
convertView = inflater.inflate(R.layout.singlepost, parent, false);
holder = new ViewHolder();
holder.bomb = (ImageView) convertView.findViewById(R.id.bomb);
holder.bomb.setOnClickListener(bomb_listener);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
holder.bomb.setOnClickListener(bomb_listener);
}
return convertView;
}
private OnClickListener bomb_listener = new OnClickListener()
{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("HOMEADAPTER", "BOOMB WAS CLICKED AT POSITON" pos);
holder.bomb.setImageResource(R.drawable.redheart);
}
};
static class ViewHolder {
TextView reporter;
TextView shell;
TextView sheller;
TextView likesnum;
TextView favsnum;
TextView comnum;
ImageView bomb;
ImageView star;
ImageView comment;
}
С этой новой реализацией getview я все еще не получаю точный элемент, который я собираюсь щелкнуть
Ответ №1:
Добавьте блок кода clicklistener внутри getView(), т.е. Там, где вы создаете представление,
getView(...) {
if (view == null) {
viewHolder = new ViewHolder();
view = ...inflateView code...
View bomb = view.findViewById(R.id.bomb);
bomb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// Perform action on click
//Run what ever task neccessary
}
});
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)view.getTag();
}
}
Комментарии:
1. Я делал это раньше, но по какой-то причине он не получает точный элемент, на который нажимается. например, я нажал кнопку в пункте 4, кнопка элемента 0 нажата. потому что из-за соображений производительности возвращаемый convertView может не соответствовать вашему ожидаемому представлению.
2. Какой подход вы используете в getView? можете ли вы вставить код getView
3. Имейте в виду, что ListViews максимально использует просмотры. Вот почему convertView не всегда имеет значение null. Если это ненулевое значение, convertView является экземпляром одной из уже отображаемых строк. Итак, если onClick зависит от каких-либо переменных, специфичных для этого изображения, вам нужно будет каждый раз устанавливать новый прослушиватель при нажатии, иначе это будет похоже на нажатие на другое изображение.
4. @Stephen Логика внутри onClick должна обрабатывать состояние (есть много способов сделать это, но для приложений она отличается), я не считаю, что создание другого прослушивателя является лучшим решением.
5. @66CLSjY Вы совершенно правы. Я указал самый простой способ сделать это. По общему признанию, это также было первое решение, которое пришло на ум. Хотя это также снизило бы эффективность при наличии достаточного количества элементов. В любом случае все это зависит от того факта, что Android максимально использует представление и связанные с ним данные, и это необходимо каким-то образом учитывать.
Ответ №2:
Представления реагируют на события снизу вверх. Это означает, что события начинаются с дочернего представления и передаются родительским представлениям. Если представление не может или не реагирует на событие, оно передается вверх по цепочке. Когда вы впервые нажимаете на изображение, представление изображения не OnClickListener
связано с ним и, следовательно, не может реагировать на событие. Однако при первом щелчке вы настраиваете для него прослушиватель. Итак, в следующий раз, когда вы нажмете на это изображение, у него теперь есть прослушиватель, и он может реагировать на событие. Вот почему он не отвечает должным образом при первом нажатии. Как предположил 66CLSjY, вы, вероятно, захотите переопределить getView (int position, View convertView, ViewGroup parent)
в своем адаптере списка, чтобы установить прослушиватель при добавлении изображения в список, а не при нажатии на него.
В ответ на ваш комментарий к ответу 66 имейте в виду, что ListViews максимально использует просмотры. Таким образом, даже если convertView не равен null, вам все равно нужно либо установить для него новый OnClickListener, либо каким-то образом учитывать повторное использование, или это будет похоже на то, что вы нажали на другое изображение.
Комментарии:
1. Итак, сначала я удаляю метод обработчика событий OnItemClickListener и концентрируюсь исключительно на обработке моих прослушивателей событий с помощью метода переопределения get View?
Ответ №3:
После жалобы на эту проблему и попытки ее обойти. Лично я считаю, что API ANDROID для просмотра списка ужасен и должен быть улучшен, чтобы его было легко использовать и внедрять. Я думаю, что это плохая идея вызывать ваших слушателей в методе переопределения get view
, потому что вы не всегда можете доверять системе Android, чтобы вернуть вам точное представление, в котором вы запрашиваете, из-за соображений производительности. Я цитирую для разработчиков представления списка. использование статического класса View Holder помогает только сохранять представления и быстрее получать к ним доступ, но это не помогает в обработке прослушивателей событий для определенных элементов, просматриваемых в элементе просмотра списка, и, честно говоря, я не видел никакого разумного решения в Интернете или на сайте разработчика Google.
Хорошо, после двух ночей ломки головы и бесконечного тестирования у меня наконец есть решение.
Используя setTag
и ViewHolder
реализацию, но только по-другому, превратите вашу статическую реализацию ViewHolder в представление, что я имею в виду
static class ViewHolder extends View implements OnClickListener {
public ViewHolder(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
ImageView bomb;
public void assignList(){
if(bomb != null)
bomb.setOnClickListener(this);
}
public int position = -1;
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("HOMEADAPTER", "OUR OWN STUFF");
}
}
После того, как вы сделали это в своей деятельности, где вы реализуете свою OnItemClickListener
, все, что вам нужно сделать, это получить установленный вами тег следующим образом
ViewHolder holder = (ViewHolder) view.getTag();
и это все, детка! вы выполнили 90%. последние 10%, что вам нужно сделать, — это то, что вы хотите сделать с вашим полученным представлением.