Android ExpandableListView с флажком, контролируемое состояние проверки

Друзья,

Я пытаюсь написать приложение, которое использует флажок в ExpandableListView, у меня возникла проблема, которая поддерживает состояние флажка приложения, я получил пример из здесь, моя проблема заключается в том, чтобы поддерживать проверенное состояние флажков, всякий раз, когда я проверяю один из флажков и расширяю список, флажки не имеют проверенного состояния, в котором они должны были быть. Я пытаюсь поддерживать, добавляя ArrayList, чтобы сохранить позицию магазина и перезагрузить позицию в getChildView(), но все же не достиг того, что я хочу сделать. вот мой код

public class ElistCBox extends ExpandableListActivity {

    private static final String LOG_TAG = "ElistCBox";
    ArrayList<String > chkState = new ArrayList<String>();
    static final String colors[] = {"grey","blue","yellow","red"};
    static final String shades[][] ={ { "lightgrey","#D3D3D3","dimgray","#696969", "sgi >gray 92","#EAEAEA"},
        { "dodgerblue 2","#1C86EE","steelblue >2","#5CACEE","powderblue","#B0E0E6"},
        { "yellow 1","#FFFF00", "gold 1","#FFD700","darkgoldenrod 1"," #FFB90F" },
        {"indianred 1","#FF6A6A", "firebrick 1","#FF3030", "maroon","#800000" } };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle)
    {
        super.onCreate(icicle);
        setContentView(R.layout.main); 
        SimpleExpandableListAdapter expListAdapter = new SimpleExpandableListAdapter( 
            this,
            createGroupList(),
            R.layout.group_row, new String[] { "colorName" },
            new int[] { R.id.childname }, createChildList(),
            R.layout.child_row,
            new String[] { "shadeName", "rgb" },
            new int[] { R.id.childname, R.id.rgb }
        ) { 
            @Override public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
            {
                final View v = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);

                final CheckBox chkColor = (CheckBox)v.findViewById(R.id.check1);

                if(chkState.contains(groupPosition+","+childPosition)){
                    chkColor.setChecked(true);
                }else{
                    chkColor.setChecked(false);
                }
                chkColor.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Log.e("Checkbox Onclick Listener", Integer.toString(groupPosition) + " - " + Integer.toString(childPosition));
                    }
                });
                chkColor.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        Log.e("Checkbox check change Listener", Integer.toString(groupPosition) + " - " + Integer.toString(childPosition));
                        if(chkColor.isChecked()){
                            chkState.add(groupPosition+","+childPosition);
                        } else {
                            chkState.remove(groupPosition+","+childPosition); 
                        }
                    }
                });
                return super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
            }
        };
        setListAdapter( expListAdapter );
    }

    public void onContentChanged  () {
        super.onContentChanged();
        Log.e( LOG_TAG, "onContentChanged" );
    }

    public boolean onChildClick(
            ExpandableListView parent, 
            View v, 
            int groupPosition,
            int childPosition,
            long id) {
        Log.e( LOG_TAG, "onChildClick: "+childPosition );
        CheckBox cb = (CheckBox)v.findViewById( R.id.check1 );
        if( cb != null )
        cb.toggle();
        return false;
    }

    public void  onGroupExpand  (int groupPosition) {
        Log.e( LOG_TAG,"onGroupExpand: "+groupPosition );
    }

    private List createGroupList() {
        ArrayList result = new ArrayList();
        for( int i = 0 ; i < colors.length ; ++i ) {
            HashMap m = new HashMap();
            m.put( "colorName",colors[i] );
            result.add( m );
        }
        return (List)result; 
    }

    private List createChildList() {
        ArrayList result = new ArrayList();
        for( int i = 0 ; i < shades.length ; ++i ) {
            ArrayList secList = new ArrayList();
            for( int n = 0 ; n < shades[i].length; n += 2 ) {
                HashMap child = new HashMap();
                child.put( "shadeName", shades[i][n] );
                child.put( "rgb", shades[i][n+1] ); secList.add( child );
            }
            result.add( secList );
        } 
        return result;
    }
}

Ответ 1

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

public class MyExpandableListAdapter extends BaseExpandableListAdapter {
//Variables
// Sample data set.  children[i] contains the children (String[]) for groups[i].
private String[] groups = { "People Names", "Dog Names", "Cat Names", "Fish Names" }; //headers
private String[][] children = {
        { "Arnold", "Barry", "Chuck", "David" },
        { "Ace", "Bandit", "Cha-Cha", "Deuce" },
        { "Fluffy", "Snuggles" },
        { "Goldy", "Bubbles" }
};
private String[] group_vaues = {"PN", "DN", "CN", "FN"};
private String[][] children_values = {
        { "Ar", "Ba", "Ch", "Da" },
        { "Ace", "Ban", "Cha", "Deu" },
        { "Flu", "Snu" },
        { "Gol", "Bub" }
};
ArrayList<ArrayList<Integer>> check_states = new ArrayList<ArrayList<Integer>>();

private Context context;

//Constructors
public MyExpandableListAdapter() {

}

public MyExpandableListAdapter(Context c) {
    this.context = c;
}

//Set Methods
public void setGroupsAndValues(String[] g, String[] v) {
    this.groups = g;
    this.group_vaues = v;
}

public void setChildrenAndValues(String[][] c, String[][] v) {
    this.children = c;
    this.children_values = v;
    //initialize the states to all 0;
    for(int i = 0; i < c.length; i++) {
        ArrayList<Integer> tmp = new ArrayList<Integer>();
        for(int j = 0; j < c[i].length; j++) {
            tmp.add(0);
        }
        check_states.add(tmp);
    }
}

//Get Methods
public Object getChild(int groupPosition, int childPosition) {
    return children[groupPosition][childPosition];
}

public long getChildId(int groupPosition, int childPosition) {
    return childPosition;
}

public int getChildrenCount(int groupPosition) {
    return children[groupPosition].length;
}

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


   LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   grid = inflater.inflate(R.layout.specialty_list_item, parent, false);

   final int grpPos = groupPosition;
   final int childPos = childPosition;

    TextView header = (TextView)grid.findViewById(R.id.title);
    header.setText(getChild(groupPosition, childPosition).toString());
    final View tick = grid.findViewById(R.id.image);
    if(check_states.get(grpPos).get(childPos) == 1)
        tick.setVisibility(View.VISIBLE);
    else
        tick.setVisibility(View.GONE);

    grid.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
            check_states.get(grpPos).set(childPos, 1);
            tick.setVisibility(View.VISIBLE);
        }
    });

    return grid;
}

public Object getGroup(int groupPosition) {
    return groups[groupPosition];
}

public int getGroupCount() {
    return groups.length;
}

public long getGroupId(int groupPosition) {
    return groupPosition;
}

public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
        ViewGroup parent) {
    View grid;

    if(convertView==null){
       grid = new View(context);
       LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
       grid = inflater.inflate(R.layout.specialty_header, parent, false);
    }else{
       grid = (View)convertView;
    }

    TextView header = (TextView)grid.findViewById(R.id.specialty_header);
    header.setText(getGroup(groupPosition).toString());


    return grid;
}

public boolean isChildSelectable(int groupPosition, int childPosition) {
    return true;
}

public boolean hasStableIds() {
    return true;
}

}

Ответ 2

У меня также есть эта проблема. Наконец, я нашел основную причину и решение. Чтобы исправить это, вместо установки checkState для checkBox вы должны установить его содержащий listView checkState.

    public class MyExpandableListViewAdapter extends BaseExpandableListAdapter {
 ....

    private boolean[][] checkedState;

    private void prepareData() {
          checkedState =new boolean[itemData.length][]; 

          for (int i=0; i<itemData.length; i++) {
              groupData.append(i, String.format("Group %d", i));
              checkedState[i] = new boolean[itemData[i].length];
              Arrays.fill(checkedState[i],false);
          }
    }

    @Override
    public View getChildView(final int groupPosition, final int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {
        View itemView = convertView;
        final ViewHolder vh;
        if (itemView == null) {
           LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
           itemView = inflater.inflate(R.layout.item_view, null);
           vh = new ViewHolder();
           vh.layout = (CheckableLinearLayout)itemView.findViewById(R.id.layout);
           itemView.setTag(vh);
        } else {
           vh = (ViewHolder)itemView.getTag();
        }

        final ExpandableListView listView = ((ExpandableListView)((MainActivity)context).findViewById(R.id.list));
        final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
        listView.setItemChecked(position, checkedState[groupPosition][childPosition]);

        vh.layout.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
        ((CheckableLinearLayout)v).toggle();
            checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition]; 
            listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked());
         }
     });
     return itemView;
  }
  ...
}

Ответ 3

ExpandableListView с мультиселекцией. Протестировано по API 4.3 и 4.0.3 Этот код также правильно обрабатывает изменение ориентации экрана. Блокирующие группы, созданные для правильной работы с выбранными элементами через SparseBooleanArray.

Я надеюсь, что этот пример кода поможет:)

Деятельность

ExpandableListView list;
ArrayList<YouCat> cat = new ArrayList<YouCat>();
private YourAdapter mAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout);
    list = (ExpandableListView)findViewById(R.id.list);
    mAdapter = new YourAdapter(this, list, cat);
    if(savedInstanceState == null)
        //collect your data
    list.setAdapter(mAdapter);
    list.setItemsCanFocus(false);
    list.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
    list.setOnChildClickListener(this);
    list.setOnGroupClickListener(this);
}

public boolean onGroupClick(ExpandableListView parent, View v,
            int groupPosition, long id) {
        return cat.get(groupPosition).selected;
}

public boolean onChildClick(ExpandableListView parent, View v,
            int groupPosition, int childPosition, long id) {
        YouCat cat = new YouCat();
        YouSubCat subcat = new YouSubCat();
        subcat = cat.get(groupPosition).sub.get(childPosition);
        subcat.selected = !cat.get(groupPosition).sub.get(childPosition).selected;
        cat.get(groupPosition).sub.set(childPosition, subcat);

        boolean isGroupHasSelected = false;
        for(int i = 0; i < cat.get(groupPosition).sub.size() && !isGroupHasSelected; i ++){
            isGroupHasSelected = cat.get(groupPosition).sub.get(i).selected;
        }
        cat = cat.get(groupPosition);
        cat.selected = isGroupHasSelected;
        cat.set(groupPosition, cat);
        //mAdapter.notifyDataSetChanged();

        int position = parent.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
        parent.setItemChecked(position, subcat.selected);

        return true;
}

 public void onRestoreInstanceState(Bundle savedInstanceState) {
     super.onRestoreInstanceState(savedInstanceState);
     //restore data 
     cat = (ArrayList<YouCat>) savedInstanceState.getSerializable("cat");
     Type selType = new TypeToken<SparseBooleanArray>() {}.getType();
     SparseBooleanArray checked = new Gson().fromJson(savedInstanceState.getString("sel"), selType);
     //set new data to adapter and refresh
     mAdapter.refreshList(cat);
 }


 public void onSaveInstanceState(Bundle savedInstanceState) {
     super.onSaveInstanceState(savedInstanceState);
     //save data and selection from list to bundle
     savedInstanceState.putSerializable("cat", cat);
     savedInstanceState.putString("sel", new Gson().toJson(list.getCheckedItemPositions()).toString());
 }

Адаптер

public class YouAdapter extends BaseExpandableListAdapter{

    private Context context;
    private List<YouCat> mGroupCollection;
    private ExpandableListView mExpandableListView;

    public YouAdapter(Context context, ExpandableListView pExpandableListView,
            List<YouCat> pGroupCollection) {
        this.context = context;
        this.mGroupCollection = pGroupCollection;
        this.mExpandableListView = pExpandableListView;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mGroupCollection.get(groupPosition).sub.get(childPosition).name;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    class ChildHolder {
    CheckBox checkBox;
    TextView name, desc;
   }

    @Override
    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {
        ChildHolder childHolder;
        if( convertView == null ){
            convertView = LayoutInflater.from(context).inflate(R.layout.childrow, null);
            childHolder = new ChildHolder();
            childHolder.checkBox = (CheckBox) convertView.findViewById(R.id.myCheckBox);
            childHolder.name=(TextView)convertView.findViewById(R.id.textView1);
            childHolder.desc=(TextView)convertView.findViewById(R.id.textView2);
            convertView.setTag(childHolder);
       }else{
            childHolder = (ChildHolder) convertView.getTag(); 
       }
        childHolder.name.setText(mGroupCollection.get(groupPosition).sub.get(childPosition).name);
        childHolder.desc.setText(mGroupCollection.get(groupPosition).sub.get(childPosition).desc);
        childHolder.checkBox.setChecked(mGroupCollection.get(groupPosition).sub.get(childPosition).selected);

        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mGroupCollection.get(groupPosition).sub.size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mGroupCollection.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return mGroupCollection.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    class GroupHolder {
      TextView title;
   }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        GroupHolder groupHolder;
       if( convertView == null ){
            convertView = LayoutInflater.from(context).inflate(R.layout.grouplayout,null);
            groupHolder = new GroupHolder();
            groupHolder.title = (TextView)convertView.findViewById( R.id.text1 );
            convertView.setTag(groupHolder);
       }else{
            groupHolder = (GroupHolder) convertView.getTag(); 
       }
       groupHolder.title.setText(mGroupCollection.get(groupPosition).name);
       return convertView;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    public void refreshList(List<YouCat> collection){
        mGroupCollection = collection;
        notifyDataSetChanged();
        for(int g = 0; g < mGroupCollection.size(); g ++){
            if(mGroupCollection.get(g).selected)
                mExpandableListView.expandGroup(g);
            else
                mExpandableListView.collapseGroup(g);
        }
    }

}

Класс YouCat

public class YouCat implements Serializable {
        private static final long serialVersionUID = 2070450081971040619L;
        public String name = null;
        public boolean selected = false;
        public ArrayList<YouSubCat> sub = new ArrayList<YouSubCat>();
}

Класс YouSubCat

public class YouSubCat implements Serializable {
    private static final long serialVersionUID = -1487507723105914936L;
    public String name = null, desc = null;
    public boolean selected = false;
}

Макет детской строки

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <CheckBox
        android:id="@+id/myCheckBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:clickable="false"
        android:focusable="false" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@+id/myCheckBox"
        android:text="TextView"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/textView1"
        android:text="TextView" />

</RelativeLayout>

Групповая компоновка

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="8dp" >

    <TextView
        android:id="@+id/text1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
        android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

Получить выбранные дочерние элементы

final SparseBooleanArray checkedItems = list.getCheckedItemPositions();
for (int i = 0; i < checkedItems.size(); i++) {
  if(checkedItems.valueAt(i))
    data = ((String)list.getItemAtPosition(checkedItems.keyAt(i)));
}

Ответ 4

Расширяемый ListView с флажком.

Мы можем получить полный пример в github, который поддерживает состояние флажка расширяемого списка.

Нажмите ссылку, чтобы получить проект студии Android
https://github.com/bhat-dinesh/ExpandableListViewWithCheckBox

Надеюсь, это поможет:)