How to know which view inside a specific ListView item that was clicked
Solution 1
You can do it. You need to modify your getView method:
@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
}
...
}
Solution 2
I used an idea from Miga's Hobby Programming.
The key is calling performItemClick() from the new onClick listener. This passes the click on through to the onItemClick() that's already being used for the listview. It's so quick and easy, I feel like I'm cheating.
Here's getView(), from the list adapter:
@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...
}
And the 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();
}
}
Solution 3
ListView recycles the row view objects and assigns fresh data on them when "getView" is called, so the approach to use, is to add a listener in the getView function. Here is a code sample from an app that shows how that is done:
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;
}
Related videos on Youtube
Comments
-
Henrik almost 2 years
I'm having a
ListView
with my own custom adapter derived from aBaseAdapter
. Each item in theListView
has sub items such asImageView
andTextView
.How can I know which one of these sub items the user clicked? Is it possible to attach a listener in the
getView
function for example, or could that be a problem?/ Henrik
Edit: Currently I have a
onItemClick
in the Activity which contains theListView
. Is there any good way to know which sub item in a specific item in the ListView which has been pressed by checking the params in theonItemClick
.@Override public void onItemClick(AdapterView<?> a, View v, int pos, long id) { . . }
-
Henrik over 12 yearsIf I do like this I get the click for that particualar ImageView, but the onItemClick disappears, i.e. the clicking of all other areas of the item (mListView.setOnItemClickListener(this);) Is it possible to combine these two without adding a item-listener for all sub-view in that particular item?
-
Henrik over 12 yearsI lost that onItemClickListener-callback, i.e. it isn't called, only the listener for that ImageButton is called
-
Plastic Sturgeon over 12 yearsThere is no reason you cannot use both approaches. But keep in mind, there is no way to know which child was clicked in itemClicked, because ti just gives you the view and position. So you will get false positives. But it is not too much work to add listeners for the other child views within a row. That is the approach I would suggest, unless the itemSelect function should be called in all cases, including when the area with a clickListener are clicked.
-
Henrik over 12 yearsThis worked fine, by problems was I switched to a ImageButton. And that did not work as expected. For others, see this question also: stackoverflow.com/questions/6116583/…
-
younes0 over 9 yearsclean solution that decouples event propagation from event handling