ExpandableListView: неправильная groupPosition возвращается, если есть расширенный childView

У меня есть ExpandableListView; отдельный элемент (групповой элемент) списка имеет FrameLayout, который содержит ToggleButton. Я сделал это для того, чтобы увеличить сенсорную область кнопки. Я использую кнопку, чтобы расширить дочерний вид элемента группы, к которому он принадлежит.
Не может быть двух отмеченных кнопок одновременно, потому что когда проверяется одна, предыдущая проверенная кнопка не проверяется.
Теперь, когда я в первый раз нажимаю на кнопку элемента, он переключается хорошо; когда, после этого, я нажимаю на один из другого элемента, кнопка, которая переключается, находится в положении "положение нажатой кнопки" +1.
Если, однако, я нажал на кнопку последнего элемента, кнопка, которая будет переключаться, - это кнопка в положении "положение переключаемой кнопки" +1 (это означает, что если я сначала переключаю элемент 1, то нажимаю кнопку последнего элемента элемент 2 будет переключаться; повторное нажатие на последний элемент переключит элемент 3, затем элемент 4, элемент 5 и т. д., пока, наконец, последний элемент не переключится).

вот код адаптера:

public class CustomList extends BaseExpandableListAdapter {

private final Activity context;
public List<Item> names;//Item is a custom object
public boolean[] buttons;
public int lastChecked;
private final int imageId = R.drawable.item1;
private ExpandableListView list;

public CustomList(Activity context, List<Item> names, ExpandableListView theListView) {

    this.context = context;
    this.names = names;
    this.buttons = new boolean[names.size()];
    this.lastChecked = -1;
    this.list = theListView;
}

private static class GroupHolder {

    TextView txtTitle;
    TextView txtData;
    ImageView imageView;
    ToggleButton toggle;
    FrameLayout frame;
}

public View getGroupView(final int position, boolean isExpanded, View convertView, ViewGroup parent) {

    GroupHolder holder;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_single, null);

        holder = new GroupHolder();

        holder.txtTitle = (TextView) convertView.findViewById(R.id.text);
        holder.txtData = (TextView) convertView.findViewById(R.id.numberOfFiles);
        holder.imageView = (ImageView) convertView.findViewById(R.id.img);
        holder.toggle = (ToggleButton) convertView.findViewById(R.id.toggle);
        holder.frame = (FrameLayout) convertView.findViewById(R.id.frame);

        holder.frame.setOnTouchListener(new OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {

                if(event.getAction() == MotionEvent.ACTION_UP) {

                    if(lastChecked != -1) {//if there's a checked button
                        buttons[lastChecked] = !buttons[lastChecked];//uncheck it

                    if(position == lastChecked)//if I clicked on the last checked button 
                        lastChecked = -1;//there's no checked button
                    else {
                        buttons[position] = !buttons[position];//check the button
                        lastChecked = position;//and set it as the last checked one
                    }

                    notifyList();
                }

                return false;
            }           
        });

        convertView.setTag(holder);

    } else {

        holder = (GroupHolder) convertView.getTag();
    }

    holder.txtTitle.setText(names.get(position).getName());

    holder.txtData.setText(names.get(position).getData());

    holder.imageView.setImageResource(imageId);

    holder.toggle.setChecked(buttons[position]);

    if(holder.toggle.isChecked()) {

        if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
            list.expandGroup(position);
        else
            list.expandGroup(position, true);
    } else {

        list.collapseGroup(position);
    }

    return convertView;
}

private static class ChildHolder {

    TextView details;
    TextView send;
    TextView other;
}

public View getChildView(final int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {

    ChildHolder holder;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_child, null);

        holder = new ChildHolder();

        holder.details = (TextView) convertView.findViewById(R.id.details);
        holder.send = (TextView) convertView.findViewById(R.id.send);
        holder.other = (TextView) convertView.findViewById(R.id.other);

        convertView.setTag(holder);

    } else {

        holder = (ChildHolder) convertView.getTag();
    }

    holder.details.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {

            buttons[lastChecked] = !buttons[lastChecked];//uncheck the only checked button (it always exists at this point)
            lastChecked = -1;//there's no checked button

            notifyList();
            //*call some method in the main activity*
        }
    });

    holder.send.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {

            buttons[lastChecked] = !buttons[lastChecked];//uncheck the only checked button (it always exists at this point)
            lastChecked = -1;//there's no checked button

            notifyList();
            //*call some method in the main activity*
        }
    });

    holder.other.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {

            buttons[lastChecked] = !buttons[lastChecked];//uncheck the only checked button (it always exists at this point)
            lastChecked = -1;//there's no checked button

            notifyList();
            //*call some method in the main activity*
        }
    });

    return convertView;
}

public void notifyList() {

    this.notifyDataSetChanged();
}

Как вы можете видеть, в getGroupView дочерний элемент раскрывается или сворачивается в зависимости от значения элемента в логическом массиве, которое соответствует позиции его представления в списке. Я вызываю notifyDataSetChanged(), чтобы обновить список.
в основном упражнении я устанавливаю onGroupClickListener в ExpandableListView и возвращаю true в onGroupClick, чтобы не раскрывать и не сворачивать дочерние представления при щелчке по элементам группы (поскольку для этого я использую кнопки ToggleButtons).

1 ответ

Решение

Хорошо, это была очень хромая ошибка. Мне приходилось устанавливать OnTouchListener для FrameLayout каждый раз, когда вызывался getGroupView, а не только в первый раз. Итак, правильный код метода таков:

public View getGroupView(final int position, boolean isExpanded, View convertView, ViewGroup parent) {

    GroupHolder holder;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_single, null);

        holder = new GroupHolder();

        holder.txtTitle = (TextView) convertView.findViewById(R.id.text);
        holder.txtData = (TextView) convertView.findViewById(R.id.numberOfFiles);
        holder.imageView = (ImageView) convertView.findViewById(R.id.img);
        holder.toggle = (ToggleButton) convertView.findViewById(R.id.toggle);
        holder.frame = (FrameLayout) convertView.findViewById(R.id.frame);

        convertView.setTag(holder);

    } else {

        holder = (GroupHolder) convertView.getTag();
    }

    holder.txtTitle.setText(names.get(position).getName());

    holder.txtData.setText(names.get(position).getData());

    holder.imageView.setImageResource(imageId);

    holder.frame.setOnTouchListener(new OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {

            if(event.getAction() == MotionEvent.ACTION_UP) {

                if(lastChecked != -1) {//if there's a checked button
                    buttons[lastChecked] = !buttons[lastChecked];//uncheck it

                if(position == lastChecked)//if I clicked on the last checked button 
                    lastChecked = -1;//there's no checked button
                else {
                    buttons[position] = !buttons[position];//check the button
                    lastChecked = position;//and set it as the last checked one
                }

                notifyList();
            }

            return false;
        }
    });

    holder.toggle.setChecked(buttons[position]);

    if(holder.toggle.isChecked()) {

        if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
            list.expandGroup(position);
        else
            list.expandGroup(position, true);
    } else {

        list.collapseGroup(position);
    }

    return convertView;
}
Другие вопросы по тегам