Skip to content Skip to sidebar Skip to footer

How To Know Which View Inside A Specific Listview Item That Was Clicked

I'm having a ListView with my own custom adapter derived from a BaseAdapter. Each item in the ListView has sub items such as ImageView and TextView. How can I know which one of the

Solution 1:

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:

@Overridepublic View getView(finalint position, View convertView, final ViewGroup parent) {

    // Check if an existing view is being reused, otherwise inflate the viewif (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(newView.OnClickListener() {
        @OverridepublicvoidonClick(View v) {
            ((ListView) parent).performItemClick(v, position, 0);
        }
    });
    // do stuff...
}

And the onItemClick():

@OverridepublicvoidonItemClick(AdapterView adapterView, View view, int position, long id) {

    longviewId= 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 2:

You can do it. You need to modify your getView method:

@Overridepublic View getView(finalint position, View row, final ViewGroup parent) {
    ...     
    YourWrapperwrapper=null;
    if (row == null) {
        row = getLayoutInflater().inflate(R.layout.your_row, parent, false);
        wrapper = newYourWrapper(row);
        row.setTag(wrapper);
    } else {
        wrapper = (YourWrapper) row.getTag();
    }

    wrapper.yourSubView.setOnClickListener(newView.OnClickListener()   
    {               
    @OverridepublicvoidonClick(View v) {
        // do something
    }
    ...
}

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:

privateclassDeletePlayerAdapterextendsArrayAdapter<Player> {
        Context context;
        int layoutResourceId;
        ArrayList<Player> data;

        publicDeletePlayerAdapter(Context context, int layout,
                ArrayList<Player> list) {
            super(context, layout, list);
            this.layoutResourceId = layout;
            this.context = context;
            this.data = list;
        }

        @Overridepublic View getView(finalint position, View convertView,
                ViewGroup parent) {
            Viewrow= convertView;
            PlayerHolderholder=null;
            if (row == null) {
                LayoutInflaterinflater= ((Activity) context)
                        .getLayoutInflater();
                row = inflater.inflate(layoutResourceId, parent, false);
                holder = newPlayerHolder();
                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(newOnClickListener() {
                //// Here is the magic sauce that makes it work.//privateintpos= position;

                publicvoidonClick(View v) {
                    ImageButtonb= (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;
                    }
                }
            });
            Playerp= 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;
        }

    }

    staticclassPlayerHolder {
        TextView player_number;
        TextView player_name;
        ImageButton seeded_button;
    }

Solution 4:

Since you have only an ImageView and a TextView, you can change your ImageView to ImageButton. You can then add a listener on the ImageButton that will be called if the user clicks on the image. If he clicks anywhere else within the item (including the TextView), the onItemclicklistener will be called. This is much simpler i think.

Solution 5:

I came up with a generic and reusable solution. Instead of extending a concrete list adapter and modifying the getView() method, I created a new class implementing the ListAdapter interface that blindly forwards almost everything to another ListAdapter except getView(). It looks like this:

publicclassSubClickableListAdapterimplementsListAdapter {

    publicstaticinterfaceOnSubItemClickListener {
        publicvoidonSubItemClick(View subView, int position);
    }
    private ListAdapter other;

    private SparseArray<OnSubItemClickListener> onClickListeners;

    publicSubClickableListAdapter(ListAdapter other) {
        this.other = other;
        onClickListeners = newSparseArray<OnSubItemClickListener>();
    }

    publicvoidsetOnClickListener(int id, OnSubItemClickListener listener) {
        onClickListeners.put(id, listener);
    }

    publicvoidremoveOnClickListener(int id) {
        onClickListeners.remove(id);
    }

    @Overridepublic View getView(finalint position, View convertView, ViewGroup parent) {
        Viewview= other.getView(position, convertView, parent);
        for(inti=0; i < onClickListeners.size(); i++) {
            ViewsubView= view.findViewById(onClickListeners.keyAt(i));
            if (subView != null) {
                finalOnSubItemClickListenerlistener= onClickListeners.valueAt(i);
                if (listener != null) {
                    subView.setOnClickListener(newOnClickListener() {
                        @OverridepublicvoidonClick(View v) {
                            listener.onSubItemClick(v, position);
                        }
                    });
                }
            }
        }
        return view;
    }

    // other implemented methods
}

The other implemented methods simply look like the following one:

@OverridepublicObjectgetItem(int position) {
    return other.getItem(position);
}

To use it, simply instantiate it supplying any other ListAdapter (be it ArrayAdapter or SimpleCursorAdapter or anything else). Then call setOnClickListener() for each view where you want to listen on the clicks, giving its id in the id parameter, and your listener in the listener parameter. To get the row id for the row which was clicked, call the getItemIdAtPosition(position) method of your ListView (which you have to get some other way, because it's not given as parameter to your callback, but that shouldn't be a big problem in most cases).

The advantage of this solution is that it can be used with any ListAdapter. So if your application has several ListViews, each using different underlying views, or even different adapters, you don't have to create a new adapter class for each one.

The problem with this is the same as with all the other solutions: the OnItemClick() of the ListView won't be called if you click on a view that you registered a listener for. For views that you didn't register a listener, this callback will be called though. So, for example, you have an activity for your list item that contains two text fields and a button, and you register a listener for the button, then clicking on the button won't call the OnItemClick() of the ListView, but your callback instead. Clicking on anywhere else calls OnItemClick().

Post a Comment for "How To Know Which View Inside A Specific Listview Item That Was Clicked"