如何知道单击的特定ListView项中的哪个视图

时间:2011-12-15 21:49:26

标签: android listview adapter

我有ListView我自己的自定义适配器派生自BaseAdapterListView中的每个项目都包含ImageViewTextView等子项。

我如何知道用户点击了哪些子项目?例如,是否可以在getView函数中附加侦听器,或者这可能是个问题?

/亨里克

修改:目前,我在活动中有onItemClick,其中包含ListView。有没有什么好方法可以通过检查onItemClick中的参数来了解ListView中特定项目中的哪个子项目。

@Override 
public void onItemClick(AdapterView<?> a, View v, int pos, long id) {
.
.
}

5 个答案:

答案 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接口的新类,它盲目地将几乎所有内容转发给另一个ListAdaptergetView()除外。它看起来像这样:

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