Как вы изменяете видимость виджетов внутри отдельных строк просмотра списка с onlistitemclick в Android? - PullRequest
3 голосов
/ 06 декабря 2011

Моя конечная цель - изменить источник информации в этого урока с массива на курсор. Вот ссылка на полный код . Суть в том, что вы щелкаете строку в списке, и тело открывается под указанным заголовком, и вы снова нажимаете на него, и тело исчезает. Я не хочу вспоминать, открыта ли заметка, и при этом я не стремлюсь держать ее открытой посредством повторного использования представления, и не закрываю все остальные, когда вы открываете одну или любую другую причудливую перестановку, о которой я могу думать с макушки головы.

В основном все работает, но когда срабатывает обработчик события onListItemClick, изменяется видимость и notifyDataSetChanged() s, список делает странные вещи, включая два щелчка, чтобы изменить видимость, и не переоценивает себя, приводя к строке списка только создавая место для себя каждый третий щелчок или около того.

Предыдущая попытка привела к совершенно рабочему списку, за исключением того, что при щелчке фрагмент в каждой строке, которую я хотел скрыть и показать, будет скрывать и показывать, а список в учебнике работает отлично, но, конечно, используются статические размеры. во всем, так что это немного больше, чем шаблон.

Я убежден, что проблема в том, чтобы либо получить информацию о видимости, прикрепленную к строке списка, либо изменить ее после того, как она была установлена.

Вот это onListItemClick:

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    ((NotesCursorAdapter) getListAdapter()).toggle(position, v);
}

с методом переключения внутри NotesCursorAdapter:

    public void toggle(int position, View view) {
        ViewHolder holder = (ViewHolder) view.getTag();

        holder.mExpanded[position] = !holder.mExpanded[position];
        notifyDataSetChanged();
    }

ViewHolder вне NotesCursorAdapter:

static class ViewHolder {
    public TextView title;
    public TextView body;
    public boolean mExpanded[];
}

и сам NotesCursorAdapter:

class NotesCursorAdapter extends CursorAdapter {

    private static final int VISIBLE = 0;
    private static final int GONE = 8;

    public NotesCursorAdapter(Context context, Cursor c) {
        super(context, c);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View rowView = inflater.inflate(R.layout.row, null, true);

        ViewHolder holder = new ViewHolder();
        holder.title = (TextView) rowView
                .findViewById(R.id.title);
        holder.body = (TextView) rowView
                .findViewById(R.id.body);
        holder.mExpanded = new boolean[cursor.getCount()];
        rowView.setTag(holder);

        return rowView;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ViewHolder holder = (ViewHolder) view.getTag();

        holder.title.setText(cursor.getString(cursor
                .getColumnIndexOrThrow(DbAdapter.KEY_TITLE))
                + holder.mExpanded[cursor.getPosition()]);
        holder.body.setText(cursor
                .getString(cursor
                        .getColumnIndexOrThrow(DbAdapter.KEY_BODY)));
        holder.body
                .setVisibility(holder.mExpanded[cursor.getPosition()] ? VISIBLE : GONE);

    }

    public void toggle(int position, View view) {
        ViewHolder holder = (ViewHolder) view.getTag();

        holder.mExpanded[position] = !holder.mExpanded[position];
        notifyDataSetChanged();
    }
}

Я не знаю, где искать дальше. Мне нужно сделать свой собственный метод getView()? Получу ли я что-нибудь полезное из getItem()? Я полностью схожу с ума от попытки использовать listview как это?

Я провел больше исследований, и код работает, но события при нажатии, похоже, влияют на противоположные представления. Под этим я подразумеваю, что при нажатии на верхний элемент списка он влияет на нижний элемент списка. Когда вы нажимаете второе сверху, оно воздействует на второе снизу. Если есть нечетное количество элементов списка, средний элемент списка работает отлично. Каким-то образом любой способ, которым я использую, чтобы определить идентификатор представления, которое я выполняю, переворачивается. Есть ли в списке вид вещей снизу вверх?

Ответы [ 2 ]

1 голос
/ 07 декабря 2011

Я только что реализовал нечто похожее на это из List6 API Demo.Мой работает отлично (все, что у меня было проблемы с фокусировкой из ImageButton).Я использовал SimpleCursorAdapter, однако, я полагаю, вы могли бы использовать CursorAdapter.Я немного изменил твой код.

Не уверен, почему вы также добавили параметр View, поэтому я убрал его.

private ArrayList<Boolean> mExpanded;

@Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        ((NotesCursorAdapter) getListAdapter()).toggle(position);
    }

Ваш ViewHolder.Довольно просто, просто конструктор получает параметры из вашего getView.

private class ViewHolder {
private TextView title;
private TextView body;

public ViewHolder(View convertView, boolean expanded) {

title = (TextView) convertView.findViewById(R.id.title);
body = (TextView) convertView.findViewById(R.id.body);

//not sure if you need this...
//body.setVisibility(expanded ? View.VISIBLE : View.GONE);
}

public void setTitle(int position) {
    cursor.moveToPosition(position);
    title.setText(cursor.getString(cursor
        .getColumnIndexOrThrow(PowersDbAdapter.KEY_TITLE)));
}

public void setBody(int position) {
    cursor.moveToPosition(position);
    body.setText(cursor.getString(cursor
                .getColumnIndexOrThrow(PowersDbAdapter.KEY_BODY)));
}

public void setExpanded(boolean expanded) {
    body.setVisibility(expanded ? View.VISIBLE : View.GONE);
    }       
}

Вот ваш пользовательский ListAdapter.Я не уверен, почему вы хотели использовать bindView и newView с ViewHolder, Android заботится об этом с помощью bindView и newViews.Но вам нужно использовать ViewHolder в этом случае, поэтому необходим getView.

private class NotesCursorAdapter extends SimpleCursorAdapter {

private Cursor cursor;
private LayoutInflater inflater;

public NotesCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to) {
    super(context, layout, cursor, from, to);
    this.cursor = cursor;
    inflater = LayoutInflater.from(context);
    mExpanded = new ArrayList<Boolean>();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;          
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.row, parent, false);

        populateExpanded();

        holder = new ViewHolder(convertView, mExpanded.get(position));

        convertView.setTag(holder);
    }
    else {
        holder = (ViewHolder) convertView.getTag();
    }
        holder.setTitle(position);
        holder.setBody(position);
        holder.setExpanded(mExpanded.get(position));

        return rowView;
}

private void populateExpanded() {
    // We want our hidden TextView to not be expanded initially
    for (int i = 0; i < cursor.getCount(); i++) {
        mExpanded.add(false);
    }
}

public void toggle(int position) {
if (mExpanded.get(position) == false) {
    mExpanded.set(position, true);
}
else {
    mExpanded.set(position, false);
}
    notifyDataSetChanged();
    }
}

Вот как вы можете отобразить его с помощью SimpleCursorAdapter

setListAdapter(new NotesCursorAdapter(MyClass.this, R.layout.row, cursor,
            new String[] { "my_title", "my_body" }, new int[] { R.id.MyTitleTextView, R.id.MyBodyTextView }));
0 голосов
/ 09 декабря 2011

К, я понял это. Настройки отображались неправильно, потому что ListView имеет два слоя: слой View и слой данных. То, как андроид перерабатывает представления в ListView, означает, что то, какое представление используется для отображения данных, не имеет значения. Таким образом, чтобы использовать CursorAdapter, информация View передается в метод newView (), а информация о данных из Cursor - в метод bindView (). Вот исправленный материал:

Здесь мало что изменилось, только пропущено то, что нужно:

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    ((NotesCursorAdapter) l.getAdapter()).toggle(position);
}

Держатель представления получает только информацию, необходимую для построения представления, но не любую информацию в представлении, включая видимое состояние:

static class ViewHolder {
    public TextView title;
    public TextView body;
    public Button button;
}

Видимое состояние отслеживается в массиве как свойство адаптера. Информация о представлении находится в методе newView (), а информация о данных - в методе bindView (). Когда срабатывает notifyDataSetChanged (), все представления перерабатываются, и данные переупорядочиваются. Поскольку информация о представлении и информация о данных являются отдельными, не имеет значения, какое представление сопоставляется с какими данными.

    class NotesCursorAdapter extends CursorAdapter {

    private boolean[] expandedArray;

    public NotesCursorAdapter(Context context, Cursor c) {
        super(context, c);
        expandedArray = new boolean[c.getCount()];
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View rowView = inflater.inflate(R.layout.row, parent, false);

        ViewHolder holder = new ViewHolder();
        holder.title= (TextView) rowView
                .findViewById(R.id.title);
        holder.body= (TextView) rowView
                .findViewById(R.id.body);
        holder.button= (Button) rowView
                .findViewById(R.id.button);

        rowView.setTag(holder);
        return rowView;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ViewHolder holder = (ViewHolder) view.getTag();

        holder.title.setText(cursor.getString(cursor
                .getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)));
        holder.body.setText(cursor.getString(cursor.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY)));
        holder.body
                .setVisibility(expandedArray[cursor.getPosition()] ? View.VISIBLE
                        : View.GONE);
        holder.button
                .setVisibility(expandedArray[cursor.getPosition()] ? View.VISIBLE
                        : View.GONE);
        holder.button.setTag(cursor.getPosition());

    }

    public void toggle(int position) {
        expandedArray[position] = !expandedArray[position];
        notifyDataSetChanged();
    }
}

А для полноты здесь приведено сопоставление из сопоставления ListAdapter, которое вызывается в onCreate (), onActivityResult () или всякий раз, когда список необходимо перезагрузить:

private void fillData() {
    notesCursor = mDbHelper.fetchAllNotes();
    startManagingCursor(notesCursor);
    NotesCursorAdapter notes = new NotesCursorAdapter(this, notesCursor);
    setListAdapter(notes);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...