Как узнать, какой вид внутри определенного элемента ListView был выбран - PullRequest
14 голосов
/ 16 декабря 2011

У меня ListView с моим собственным адаптером, полученным из BaseAdapter.Каждый элемент в ListView имеет подэлементы, такие как ImageView и TextView.

Как узнать, какой из этих субэлементов пользователь щелкнул?Можно ли, например, подключить слушателя в функции getView, или это может быть проблемой?

/ Henrik

Редактировать: В настоящее время у меня есть onItemClick в деятельности, которая содержит ListView.Есть ли хороший способ узнать, какой подпункт в определенном элементе в ListView был нажат, проверив параметры в onItemClick.

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

Ответы [ 5 ]

11 голосов
/ 22 декабря 2014

Я использовал идею из Miga's Hobby Programming .

Ключ вызывает метод executeItemClick () из нового прослушивателя onClick. Это передает щелчок на 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();

   }
}
5 голосов
/ 16 декабря 2011

Вы можете сделать это.Вам нужно изменить метод 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
    }
    ...
}
3 голосов
/ 16 декабря 2011

ListView перезаписывает объекты представления строк и назначает свежие данные при их вызове «getView», поэтому подход, который нужно использовать, заключается в добавлении прослушивателя в функцию 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;
    }
0 голосов
/ 11 сентября 2012

Я придумал универсальное и многоразовое решение.Вместо того, чтобы расширять конкретный адаптер списка и модифицировать метод 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().

0 голосов
/ 16 декабря 2011

Поскольку у вас есть только ImageView и TextView, вы можете изменить свой ImageView на ImageButton.Затем вы можете добавить слушателя в ImageButton, который будет вызываться, если пользователь нажимает на изображение.Если он щелкнет где-нибудь еще внутри элемента (включая TextView), будет вызван onItemclicklistener.Это намного проще, я думаю.

...