Я придумал универсальное и многоразовое решение.Вместо того, чтобы расширять конкретный адаптер списка и модифицировать метод getView()
, я создал новый класс, реализующий интерфейс ListAdapter
, который слепо перенаправляет почти все на другой ListAdapter
, за исключением getView()
.Это выглядит так:
public class SubClickableListAdapter implements ListAdapter {
public static interface OnSubItemClickListener {
public void onSubItemClick(View subView, int position);
}
private ListAdapter other;
private SparseArray<OnSubItemClickListener> onClickListeners;
public SubClickableListAdapter(ListAdapter other) {
this.other = other;
onClickListeners = new SparseArray<OnSubItemClickListener>();
}
public void setOnClickListener(int id, OnSubItemClickListener listener) {
onClickListeners.put(id, listener);
}
public void removeOnClickListener(int id) {
onClickListeners.remove(id);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = other.getView(position, convertView, parent);
for(int i = 0; i < onClickListeners.size(); i++) {
View subView = view.findViewById(onClickListeners.keyAt(i));
if (subView != null) {
final OnSubItemClickListener listener = onClickListeners.valueAt(i);
if (listener != null) {
subView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onSubItemClick(v, position);
}
});
}
}
}
return view;
}
// other implemented methods
}
Другие реализованные методы просто выглядят следующим образом:
@Override
public Object getItem(int position) {
return other.getItem(position);
}
Чтобы использовать его, просто создайте его экземпляр, предоставив любой другой ListAdapter
(будь тоArrayAdapter
или SimpleCursorAdapter
или что-нибудь еще).Затем вызовите setOnClickListener()
для каждого представления, где вы хотите прослушивать щелчки, указав его идентификатор в параметре id
, а своего слушателя в параметре listener
.Чтобы получить идентификатор строки для строки, по которой щелкнули, вызовите метод getItemIdAtPosition(position)
вашего ListView (который вы должны получить другим способом, потому что он не указан в качестве параметра для вашего обратного вызова, но это не должно быть большой проблемой).в большинстве случаев).
Преимущество этого решения в том, что оно может использоваться с любым ListAdapter
.Поэтому, если ваше приложение имеет несколько ListView
s, каждый из которых использует разные базовые представления или даже разные адаптеры, вам не нужно создавать новый класс адаптера для каждого из них.
Проблема с этим одна и та жекак и во всех других решениях: OnItemClick()
из ListView
не будет вызываться, если вы нажмете на представление, для которого вы зарегистрировали слушателя.Для представлений, которые вы не зарегистрировали, слушатель будет вызываться.Так, например, у вас есть действие для элемента списка, который содержит два текстовых поля и кнопку, и вы регистрируете прослушиватель для кнопки, после чего нажатие на кнопку не вызовет OnItemClick()
из ListView
,но ваш обратный звонок вместо.При нажатии в любом другом месте звонки OnItemClick()
.