我有ListView
我自己的自定义适配器派生自BaseAdapter
。 ListView
中的每个项目都包含ImageView
和TextView
等子项。
我如何知道用户点击了哪些子项目?例如,是否可以在getView
函数中附加侦听器,或者这可能是个问题?
/亨里克
修改:目前,我在活动中有onItemClick
,其中包含ListView
。有没有什么好方法可以通过检查onItemClick
中的参数来了解ListView中特定项目中的哪个子项目。
@Override
public void onItemClick(AdapterView<?> a, View v, int pos, long id) {
.
.
}
答案 0 :(得分:11)
我使用了来自Miga's Hobby Programming的想法。
关键是从新的onClick侦听器调用performItemClick()。这会将点击通过传递给已经用于列表视图的onItemClick()。这是如此快速和简单,我觉得我在作弊。
这是来自列表适配器的getView():
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.one_line, parent, false);
}
// This chunk added to get textview click to register in Fragment's onItemClick()
// Had to make position and parent 'final' in method definition
convertView.findViewById(R.id.someName).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((ListView) parent).performItemClick(v, position, 0);
}
});
// do stuff...
}
onItemClick():
@Override
public void onItemClick(AdapterView adapterView, View view, int position, long id) {
long viewId = view.getId();
if (viewId == R.id.someName) {
Toast.makeText(getActivity(), "someName item clicked", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getActivity(), "ListView clicked: " + id, Toast.LENGTH_SHORT).show();
}
}
答案 1 :(得分:5)
你可以做到。您需要修改getView方法:
@Override
public View getView(final int position, View row, final ViewGroup parent) {
...
YourWrapper wrapper = null;
if (row == null) {
row = getLayoutInflater().inflate(R.layout.your_row, parent, false);
wrapper = new YourWrapper(row);
row.setTag(wrapper);
} else {
wrapper = (YourWrapper) row.getTag();
}
wrapper.yourSubView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
// do something
}
...
}
答案 2 :(得分:3)
当调用“getView”时,ListView会回收行视图对象并为它们分配新数据,因此使用的方法是在getView函数中添加一个侦听器。以下是来自应用的示例代码示例:
private class DeletePlayerAdapter extends ArrayAdapter<Player> {
Context context;
int layoutResourceId;
ArrayList<Player> data;
public DeletePlayerAdapter(Context context, int layout,
ArrayList<Player> list) {
super(context, layout, list);
this.layoutResourceId = layout;
this.context = context;
this.data = list;
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
View row = convertView;
PlayerHolder holder = null;
if (row == null) {
LayoutInflater inflater = ((Activity) context)
.getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new PlayerHolder();
holder.player_name = (TextView) row
.findViewById(R.id.player_name);
holder.player_number = (TextView) row
.findViewById(R.id.player_number);
holder.seeded_button = (ImageButton) row
.findViewById(R.id.delete_toggle);
holder.player_name.setTypeface(tf);
holder.player_number.setTypeface(tf);
row.setTag(holder);
players_array.get(position).marked_for_delete = false;
} else {
Log.d("PLAYER_ADAPTER", "NOT_NULL ROW");
holder = (PlayerHolder) row.getTag();
}
holder.seeded_button.setOnClickListener(new OnClickListener() {
//
// Here is the magic sauce that makes it work.
//
private int pos = position;
public void onClick(View v) {
ImageButton b = (ImageButton) v;
if (b.isSelected()) {
b.setSelected(false);
players_array.get(pos).marked_for_delete = false;
} else {
b.setSelected(true);
players_array.get(pos).marked_for_delete = true;
}
}
});
Player p = data.get(position);
holder.player_name.setText(p.name);
holder.player_number.setText(String.valueOf(position+1));
holder.seeded_button
.setSelected(players_array.get(position).marked_for_delete);
return row;
}
}
static class PlayerHolder {
TextView player_number;
TextView player_name;
ImageButton seeded_button;
}
答案 3 :(得分:0)
由于您只有ImageView和TextView,因此可以将ImageView更改为ImageButton。然后,您可以在ImageButton上添加一个侦听器,如果用户单击该图像,将会调用该侦听器。如果他点击项目中的任何其他位置(包括TextView),将调用onItemclicklistener。 我认为这更简单。
答案 4 :(得分:0)
我提出了一个通用且可重复使用的解决方案。我没有扩展具体的列表适配器并修改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
参数中提供其ID,并在listener
参数中显示您的侦听器。要获取被单击的行的行ID,请调用ListView的getItemIdAtPosition(position)
方法(您必须以其他方式获取,因为它没有作为回调的参数给出,但是不应该&在大多数情况下,这是个大问题。)
此解决方案的优点是它可以与任何ListAdapter
一起使用。因此,如果您的应用程序有多个ListView
,每个使用不同的底层视图,甚至不同的适配器,您就不必为每个应用程序创建一个新的适配器类。
此问题与所有其他解决方案相同:如果您单击注册了侦听器的视图,则OnItemClick()
的{{1}}将被调用。对于您没有注册监听器的视图,将调用此回调。因此,例如,您的列表项包含两个文本字段和一个按钮的活动,并为该按钮注册一个监听器,然后单击该按钮不会调用该ListView
OnItemClick()
,但是你的回调。点击其他任何地方都可以拨打ListView
。