I've created a Spinner programmatically and add it to ListView's adapter. However, I can't get the Spinner back from ListView.
//listView = (NestedListView)findViewById(R.id.exListView);
create.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Spinner spinner;
for (int i=0; i<listView.getChildCount(); i++) {
if (listView.getChildAt(i) instanceof Spinner){
spinner = (Spinner) listView.getChildAt(i);
String selection = (String) spinner.getSelectedItem();
Log.e("spinner device", selection);
}
}
}
});
My adapter
public class ExpListAdapter extends BaseExpandableListAdapter {
private ArrayList<ArrayList<String>> mGroups;
private ArrayList<DeviceObject> deviceObList;
private ArrayList<RoomSuggestion> roObjList;
private Context mContext;
public ExpListAdapter (Context context,ArrayList<ArrayList<String>> groups, ArrayList<DeviceObject> deviceObList, ArrayList<RoomSuggestion> roObjList){
mContext = context;
mGroups = groups;
this.deviceObList = deviceObList;
this.roObjList = roObjList;
}
#Override
public int getGroupCount() {
return mGroups.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return mGroups.get(groupPosition).size();
}
#Override
public Object getGroup(int groupPosition) {
return mGroups.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return mGroups.get(groupPosition).get(childPosition);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.group_view, null);
}
if (isExpanded) {
//Изменяем что-нибудь, если текущая Group раскрыта
} else {
//Изменяем что-нибудь, если текущая Group скрыта
}
Typeface lightFace = Typeface.createFromAsset(mContext.getAssets(), "font/GothamProLight.ttf");
TextView textGroup = (TextView) convertView.findViewById(R.id.textGroup);
textGroup.setTypeface(lightFace);
textGroup.setText("Thereses gate 46");
return convertView;
}
#Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.child_view, null);
}
Typeface mediumFace = Typeface.createFromAsset(mContext.getAssets(), "font/GothamProMedium.ttf");
TextView textChild = (TextView) convertView.findViewById(R.id.textChild);
textChild.setTypeface(mediumFace);
textChild.setText( mGroups.get(groupPosition).get(childPosition) );
RelativeLayout rl = (RelativeLayout) convertView.findViewById(R.id.bg_button_screen);
if( !deviceObList.get(childPosition).getProduct_id().equals("0") ) {
rl.setBackgroundColor(Color.parseColor("#4fcc54"));
} else {
rl.setBackgroundColor(Color.parseColor("#e5910d"));
}
View linearLayoutG = convertView.findViewById(R.id.container);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(10, 0, 10, 30);
linearLayoutG.setLayoutParams(layoutParams);
RelativeLayout spinnerOpen = (RelativeLayout) convertView.findViewById(R.id.spinnerOpen);
View linearLayout = convertView.findViewById(R.id.spinnerL);
ImageView imageS = (ImageView)convertView.findViewById(R.id.spinnerImage);
imageS.getLayoutParams().width = 20;
imageS.getLayoutParams().height = 20;
imageS.setImageResource(R.drawable.spin_ok);
ArrayList<String> list = new ArrayList<String>();
for (int i=0; i<roObjList.size(); i++) {
list.add(roObjList.get(i).getName() );
}
final Spinner spinner = new Spinner(mContext);
// Make sure you have valid layout parameters.
spinner.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 100));
spinner.setBackgroundResource(R.drawable.bg_spinner);
ArrayAdapter spinnerArrayAdapter = new ArrayAdapter(mContext,
R.layout.spinner_item, list);
spinner.setAdapter(spinnerArrayAdapter);
// open spinner
spinnerOpen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinner.performClick();
}
});
((LinearLayout) linearLayout).addView(spinner);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Log.e("selected", String.valueOf(parent.getItemAtPosition(position)) );
Log.e("childPosition", String.valueOf(childPosition));
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
You can try the following code:
//listView = (NestedListView)findViewById(R.id.exListView);
create.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i = 0; i < listView.getAdapter().getCount(); i++ ) {
for(int i = 0; i < listView.getChildCount(); i++ ) {
View _mainView = listView.getChildAt(i);
LinearLayout _linearLayout = _mainView.findViewById(R.id.spinnerL);
Spinner spinner = (Spinner) _linearLayout.getChildAt(0);
String selection = (String) spinner.getSelectedItem();
Log.e("spinner device", selection);
}
}
}
});
Related
I am trying to assign each of the children in my expandable listview to its proper parents, but I ended up assigning all child data to each parent in the list view.
This is my activity:
api.USER_VM_LIST(UserId)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<UserVmList>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(UserVmList userVmList) {
listVmTitle = new ArrayList<>();
listHashMap = new HashMap<>();
List<DetailsOfVmObject> detailsOfVmObjects = new ArrayList<>();
for (int i = 0; i < userVmList.getVm_data().size(); i++) {
//loop Listview RowTitle
VmObject vmObject = new VmObject(userVmList.getVm_data().get(i).getHostname(),
userVmList.getVm_data().get(i).getStatus(), userVmList.getVm_data().get(i).getImage());
listVmTitle.add(vmObject);
//Loop Listview RowChildren
DetailsOfVmObject details = new DetailsOfVmObject(userVmList.getVm_data().get(i).getFlavor(),
userVmList.getVm_data().get(i).getIp_vm());
detailsOfVmObjects.add(details);
//loop hashmap
listHashMap.put(listVmTitle.get(i),detailsOfVmObjects);
}
LayoutInflater layoutInflater = getLayoutInflater();
ViewGroup header = (ViewGroup)layoutInflater.inflate(R.layout.listview_header,expandableListView,false);
expandableListView.addHeaderView(header);
ExpandableListAdapter adapter = new ExpandableListAdapter(mContext, listVmTitle,listHashMap,detailsOfVmObjects);
expandableListView.setAdapter(adapter);
expandableListView.setOnGroupClickListener((parent, v, groupPosition, id) -> false);
}
});
}
Here is my Expandablelistadapter definition:
private Context mContext;
private List<VmObject> listVmTitle;
private HashMap<VmObject, List<DetailsOfVmObject>> listHashMap;
private List<DetailsOfVmObject> detailsOfVmObjects;
public ExpandableListAdapter(Context mContext, List<VmObject> listVmTitle, HashMap<VmObject, List<DetailsOfVmObject>> listHashMap,
List<DetailsOfVmObject> detailsOfVmObjects ) {
this.mContext = mContext;
this.listVmTitle = listVmTitle;
this.listHashMap = listHashMap;
this.detailsOfVmObjects = detailsOfVmObjects;
}
#Override
public int getGroupCount() {
return listVmTitle.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return listHashMap.get(listVmTitle.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return listVmTitle.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return listHashMap.get(listVmTitle.get(groupPosition)).get(childPosition);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final String VmHostName = listVmTitle.get(groupPosition).getHostName();
final String VmStatus = listVmTitle.get(groupPosition).getStatus();
final String VmOs = listVmTitle.get(groupPosition).getOs();
if (convertView == null){
LayoutInflater layoutInflater = (LayoutInflater)this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.expandable_row,null);
}
TextView tvHostname = (TextView) convertView.findViewById(R.id.FirstText1);
TextView tvStatus = (TextView) convertView.findViewById(R.id.SecondText2);
TextView tvOs = (TextView) convertView.findViewById(R.id.ThirdText3);
tvHostname.setText(VmHostName);
tvStatus.setText(VmStatus);
tvOs.setText(VmOs);
return convertView;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
String Flavor = detailsOfVmObjects.get(childPosition).getFlavor();
String Ip = detailsOfVmObjects.get(childPosition).getIpAddress();
if (convertView == null){
LayoutInflater layoutInflater = (LayoutInflater)this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.expandable_row_children,null);
}
TextView TvFlavor = (TextView) convertView.findViewById(R.id.expandable1);
TextView TvIp = (TextView) convertView.findViewById(R.id.expandable2);
TvFlavor.setText(Flavor);
TvIp.setText(Ip);
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
screenshot of the listview oin my current state :
Assume that the hostName is different between groups, try to prepare your data lists like below:
List<VmObject> listVmTitle = new ArrayList<>();
HashMap<VmObject, List<DetailsOfVmObject>> listHashMap = new HashMap<>();
for (int i = 0; i < userVmList.getVm_data().size(); i++) {
VmObject vmObject = new VmObject(userVmList.getVm_data().get(i).getHostname(),
userVmList.getVm_data().get(i).getStatus(), userVmList.getVm_data().get(i).getImage());
List<DetailsOfVmObject> detailsOfVmObjects;
for (int j = 0; j < listVmTitle.size(); j++) {
if (listVmTitle.get(j).getHostName().equals(vmObject.getHostName())) { // Group exists
detailsOfVmObjects = listHashMap.get(vmObject);
} else { // Group not exists
listVmTitle.add(vmObject); // Add new group
detailsOfVmObjects = new ArrayList<>(); // Create child list for the group
listHashMap.put(listVmTitle.get(i), detailsOfVmObjects);
}
DetailsOfVmObject details = new DetailsOfVmObject(userVmList.getVm_data().get(i).getFlavor(),
userVmList.getVm_data().get(i).getIp_vm());
detailsOfVmObjects.add(details);
}
}
Please note that now only two lists are needed to create the expandable list view, so make changes accordingly. Also in adapter change:
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
DetailsOfVmObject childObject = (DetailsOfVmObject)getChild(groupPosition, childPosition);
String Flavor = childObject.getFlavor();
String Ip = childObject.getIpAddress();
if (convertView == null){
LayoutInflater layoutInflater = (LayoutInflater)this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.expandable_row_children,null);
}
TextView TvFlavor = (TextView) convertView.findViewById(R.id.expandable1);
TextView TvIp = (TextView) convertView.findViewById(R.id.expandable2);
TvFlavor.setText(Flavor);
TvIp.setText(Ip);
return convertView;
}
Hope that helps!
I have a check list (Customized expandable list view) that I am populating through adapter. I want to retrieve an array from adapter to Activity on click of a text view in activity.
Activity is as follows, I want to retrieve data in onOptionsItemSelected function:
public class MyPreferencesActivity extends BaseActivity implements PreferencesContract.View, AdapterView.OnItemClickListener, ExpandableListView.OnGroupClickListener {
private PreferencesContract.Presenter mPresenterPreferences;
private Context context;
private ExpandableListView elvListView;
private ArrayList<CategoryModel> categories;
private ExpandableListAdapter ela;
private List<CategoryModel> mCategories;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_preferences);
this.context = this;
Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
setupActionbar(toolbar, getString(R.string.preferneces), true, R.drawable.ab_home);
new PreferencesPresenter(this,
Injection.provideUseCaseHandler(),
Injection.provideGetCategories(getApplicationContext())
);
mPresenterPreferences.getCategories();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_save_my_preferences, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
//listener for home
switch (menuItem.getItemId()) {
case R.id.menu_create_event:
break;
}
return super.onOptionsItemSelected(menuItem);
}
private void populateList() {
categories = new ArrayList<>();
for (int i = 0; i < mCategories.size(); i ++){
categories.add(new CategoryModel(mCategories.get(i).getCategoryName(), mCategories.get(i).getCategoryId(), mCategories.get(i).getSubCategories()));
}
}
#Override
public void onItemClick(AdapterView<?> adapterView, android.view.View view, int i, long l) {
}
#Override
public boolean onGroupClick(ExpandableListView expandableListView, android.view.View view, int i, long l) {
return false;
}
#Override
public void setLoading(boolean isActive) {}
public void initViews(){
ela = new ExpandableListAdapter(this, categories);
elvListView = (ExpandableListView) findViewById(R.id.lv_preferences);
elvListView.setAdapter(ela);
elvListView.setOnItemClickListener(this);
elvListView.setOnGroupClickListener(this);
}
#Override
public void showGetPreferencesSuccess(List<CategoryModel> categories) {
setLoading(false);
mCategories = categories;
populateList();
initViews();
}
#Override
public void showGetPreferencesFail(int errorCode) {
}
#Override
public void setPresenter(PreferencesContract.Presenter presenter) {
mPresenterPreferences = Preconditions.checkNotNull(presenter);
}
}
Adapter is as follows:
public class ExpandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private ArrayList<String> item;
private ArrayList<Boolean> itemsChecked;
private ArrayList<ArrayList<Boolean>> childChecked;
private ArrayList<ArrayList<String>> childList;
public ExpandableListAdapter(Context c, ArrayList<CategoryModel> d) {
this.context = c;
this.item = new ArrayList<>();
for (int i = 0; i< d.size(); i++){
this.item.add(d.get(i).getCategoryName());
ArrayList<String> subCat = new ArrayList<>();
for (int j = 0 ; j < d.get(j).getSubCategories().size() ; j++){
subCat.add(d.get(j).getSubCategories().get(j).getSubCategoryName());
}
childList.add(subCat);
}
itemsChecked = new ArrayList<>();
childChecked = new ArrayList<ArrayList<Boolean>>();
for (int i = 0; i < this.item.size() ; i++) {
itemsChecked.add(false);
ArrayList <Boolean>temp = new ArrayList<>();
for (int j = 0 ; j < childList.get(i).size(); j ++){
temp.add(false);
}
childChecked.add(temp);
}
}
#Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, final ViewGroup parent) {
LayoutInflater infalInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.my_preferences_list_group, null);
TextView tvName = (TextView) convertView.findViewById(R.id.tvGroupName);
final CheckBox checkBox = (CheckBox)convertView.findViewById(R.id.checkbox);
if((getChildrenCount(groupPosition) == 0 && itemsChecked.get(groupPosition))|| (getChildrenCount(groupPosition) > 0 && !(childChecked.get(groupPosition).contains(false)))) {
checkBox.setChecked(true);
}
else {
checkBox.setChecked(false);
}
checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CheckBox checkBox = (CheckBox)view;
RelativeLayout vwParentRow = (RelativeLayout)view.getParent();
TextView child = (TextView)vwParentRow.getChildAt(0);
final int position = item.indexOf(child.getText());
if (checkBox.isChecked()){
itemsChecked.set(position, true);
for (int i = 0 ; i < getChildrenCount(groupPosition); i++){
childChecked.get(groupPosition).set(i, true);
}
}
else {
itemsChecked.set(position, false);
for (int i = 0 ; i < getChildrenCount(groupPosition); i++){
childChecked.get(groupPosition).set(i, false);
}
}
ExpandableListAdapter.this.notifyDataSetChanged();
}
});
TextView tvCount = (TextView) convertView.findViewById(R.id.tv_item_count);
tvName.setText(item.get(groupPosition));
int childCount = getChildrenCount(groupPosition);
if (childCount > 0) {
tvCount.setText(getChildrenCount(groupPosition) + "items");
tvCount.setVisibility(View.VISIBLE);
}
if (isExpanded) {
}
else {
}
return convertView;
}
#Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
LayoutInflater infalInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.my_preferences_list_item, null);
TextView tvName = (TextView) convertView.findViewById(R.id.tv_item);
CheckBox checkBox = (CheckBox)convertView.findViewById(R.id.checkBox);
if (childChecked.get(groupPosition).get(childPosition))
checkBox.setChecked(true);
checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CheckBox checkBox = (CheckBox)view;
RelativeLayout vwParentRow = (RelativeLayout)view.getParent();
TextView child = (TextView)vwParentRow.getChildAt(0);
int position = -1;
for (int i = 0 ; i < childList.size(); i++){
if (childList.get(i).contains(child.getText())){
if(checkBox.isChecked()) {
childChecked.get(i).set(childList.get(i).indexOf(child.getText()) , true);
ExpandableListAdapter.this.notifyDataSetChanged();
}
else {
childChecked.get(i).set(childList.get(i).indexOf(child.getText()) , false);
ExpandableListAdapter.this.notifyDataSetChanged();
}
}
}
if (checkBox.isChecked()){
if (position >0 )
itemsChecked.set(position, true);
}
else if(position > 0) {
itemsChecked.set(position, false);
}
}
});
String s = childList.get(groupPosition).get(childPosition);
tvName.setText(s);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return childList.get(groupPosition).size();
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return childList.get(groupPosition).get(childPosition);
}
#Override
public int getGroupCount() {
return item.size();
}
#Override
public Object getGroup(int groupPosition) {
return item.get(groupPosition);
}
#Override
public long getGroupId(int groupPosition) {
return 0;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
I have an idea of sending data from Activity to Adapter.
Any help in doing it some other way?
I think it's as simple as creating a getter inside your adapter
public List<String> getItems() {
return this.item;
}
And inside onOptionsItemSelected in the activity
ela.getItems();
I have 500+ items to put in a checklist divided into categories.
My solution so far for this is to use multiple expandableListView lists and the items inside them of course.
The problem shows up when I check some of the check boxes, the get messed up and check boxes from another lists get checked and I dont know why.. Can someone throw some light here?
ExpandableListView.java
public class IngredientsExpandableList extends ExpandableListActivity {
// Create ArrayList to hold parent Items and Child Items
private ArrayList<ParentModel> parentItems = new ArrayList<ParentModel>();
private ArrayList<ChildModel> childItems = new ArrayList<ChildModel>();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Create Expandable List and set it's properties
ExpandableListView expandableList = getExpandableListView();
expandableList.setDividerHeight(0);
expandableList.setGroupIndicator(null);
expandableList.setClickable(true);
//Setting the data.
setData();
// Create the Adapter
MyExpandableAdapter adapter = new MyExpandableAdapter(parentItems, childItems);
adapter.setInflater(LayoutInflater.from(this), this);
// Set the Adapter to expandableList
expandableList.setAdapter(adapter);
expandableList.setOnChildClickListener(this);
}
public void setData(){
String[] colors = getResources().getStringArray(R.array.ingredientsColor);
String[] innerColors = getResources().getStringArray(R.array.ingredientsInnerColor);
// Set the Items of Parent
for (int i = 0; i < 10; i++){
parentItems.add(new ParentModel("ingredients "+(i+1), Color.parseColor(colors[i])));
}
// Set The Child Data
ArrayList<String> child = null;
for (int i = 0; i < parentItems.size(); i++){
child = new ArrayList<String>();
for (int k = 0; k < 4; k++){
child.add("ingredient " + (k+1));
}
childItems.add(new ChildModel(child,Color.parseColor(innerColors[i])));
}
}
public void makeToast(String string){
Toast.makeText(this, string,
Toast.LENGTH_SHORT).show();
}
public class ParentModel{
String text;
int color;
public ParentModel(String text, int color) {
this.text = text;
this.color = color;
}
public String getText() {
return text;
}
public int getColor() {
return color;
}
}
public class ChildModel{
ArrayList<String> text;
int color;
public ChildModel(ArrayList<String> text, int color) {
this.text = text;
this.color = color;
}
public ArrayList<String> getText() {
return text;
}
public int getColor() {
return color;
}
}
public class MyExpandableAdapter extends BaseExpandableListAdapter
{
private Activity activity;
private ArrayList<ChildModel> childItems;
private LayoutInflater inflater;
private ArrayList<ParentModel> parentItems;
private ArrayList<String> child;
// constructor
public MyExpandableAdapter(ArrayList<ParentModel> parents, ArrayList<ChildModel> childern)
{
this.parentItems = parents;
this.childItems = childern;
}
public void setInflater(LayoutInflater inflater, Activity activity)
{
this.inflater = inflater;
this.activity = activity;
}
// method getChildView is called automatically for each child view.
// Implement this method as per your requirement
#Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
{
child = childItems.get(groupPosition).getText();
TextView textView = null;
CheckBox checkBox = null;
LinearLayout LinearView = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.child_list, null);
}
// get the textView reference and set the value
textView = (TextView) convertView.findViewById(R.id.textView1);
textView.setText(child.get(childPosition));
LinearView = (LinearLayout) convertView.findViewById(R.id.layout);
LinearView.setBackgroundColor(childItems.get(groupPosition).getColor());
checkBox = (CheckBox) convertView.findViewById(R.id.checkBox1);
// set the ClickListener to handle the click event on child item
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
makeToast("clicked");
}
});
return convertView;
}
// method getGroupView is called automatically for each parent item
// Implement this method as per your requirement
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
{
if (convertView == null) {
convertView = inflater.inflate(R.layout.parent_list, null);
}
((CheckedTextView) convertView.findViewById(R.id.textViewGroup)).setText(parentItems.get(groupPosition).getText());
((CheckedTextView) convertView.findViewById(R.id.textViewGroup)).setBackgroundColor(parentItems.get(groupPosition).getColor());
((CheckedTextView) convertView.findViewById(R.id.textViewGroup)).setChecked(isExpanded);
return convertView;
}
#Override
public Object getChild(int groupPosition, int childPosition)
{
return null;
}
#Override
public long getChildId(int groupPosition, int childPosition)
{
return 0;
}
#Override
public int getChildrenCount(int groupPosition)
{
return childItems.get(groupPosition).getText().size();
}
#Override
public Object getGroup(int groupPosition)
{
return null;
}
#Override
public int getGroupCount()
{
return parentItems.size();
}
#Override
public void onGroupCollapsed(int groupPosition)
{
super.onGroupCollapsed(groupPosition);
}
#Override
public void onGroupExpanded(int groupPosition)
{
super.onGroupExpanded(groupPosition);
}
#Override
public long getGroupId(int groupPosition)
{
return 0;
}
#Override
public boolean hasStableIds()
{
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition)
{
return false;
}
}
}
This is because views are recycled in lists so you must store the state of the checks and make sure you set them inside the get child view. something like this
public class IngredientsExpandableList extends ExpandableListActivity {
// Create ArrayList to hold parent Items and Child Items
private ArrayList<ParentModel> parentItems = new ArrayList<ParentModel>();
private ArrayList<ChildModel> childItems = new ArrayList<ChildModel>();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Create Expandable List and set it's properties
ExpandableListView expandableList = getExpandableListView();
expandableList.setDividerHeight(0);
expandableList.setGroupIndicator(null);
expandableList.setClickable(true);
//Setting the data.
setData();
// Create the Adapter
MyExpandableAdapter adapter = new MyExpandableAdapter(parentItems, childItems);
adapter.setInflater(LayoutInflater.from(this), this);
// Set the Adapter to expandableList
expandableList.setAdapter(adapter);
expandableList.setOnChildClickListener(this);
}
public void setData(){
String[] colors = getResources().getStringArray(R.array.ingredientsColor);
String[] innerColors = getResources().getStringArray(R.array.ingredientsInnerColor);
// Set the Items of Parent
for (int i = 0; i < 10; i++){
parentItems.add(new ParentModel("ingredients "+(i+1), Color.parseColor(colors[i])));
}
// Set The Child Data
ArrayList<String> child = null;
for (int i = 0; i < parentItems.size(); i++){
child = new ArrayList<String>();
for (int k = 0; k < 4; k++){
child.add("ingredient " + (k+1));
}
childItems.add(new ChildModel(child,Color.parseColor(innerColors[i])));
}
}
public void makeToast(String string){
Toast.makeText(this, string,
Toast.LENGTH_SHORT).show();
}
public class ParentModel{
String text;
int color;
public ParentModel(String text, int color) {
this.text = text;
this.color = color;
}
public String getText() {
return text;
}
public int getColor() {
return color;
}
}
public class ChildModel{
ArrayList<String> text;
int color;
ArrayList<Boolean> checked = new ArrayList();;
public ChildModel(ArrayList<String> text, int color) {
this.text = text;
this.color = color;
for(String i:text)
{
checked.add(false);
}
}
public ArrayList<String> getText() {
return text;
}
public int getColor() {
return color;
}
}
public class MyExpandableAdapter extends BaseExpandableListAdapter
{
private Activity activity;
private ArrayList<ChildModel> childItems;
private LayoutInflater inflater;
private ArrayList<ParentModel> parentItems;
private ArrayList<String> child;
// constructor
public MyExpandableAdapter(ArrayList<ParentModel> parents, ArrayList<ChildModel> childern)
{
this.parentItems = parents;
this.childItems = childern;
}
public void setInflater(LayoutInflater inflater, Activity activity)
{
this.inflater = inflater;
this.activity = activity;
}
// method getChildView is called automatically for each child view.
// Implement this method as per your requirement
#Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
{
child = childItems.get(groupPosition).getText();
TextView textView = null;
CheckBox checkBox = null;
LinearLayout LinearView = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.child_list, null);
}
// get the textView reference and set the value
textView = (TextView) convertView.findViewById(R.id.textView1);
textView.setText(child.get(childPosition));
LinearView = (LinearLayout) convertView.findViewById(R.id.layout);
LinearView.setBackgroundColor(childItems.get(groupPosition).getColor());
checkBox = (CheckBox) convertView.findViewById(R.id.checkBox1);
checkBox.setChecked(childItems.get(groupPosition).checked.get(childPosition));
checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
childItems.get(groupPosition).checked.get(childPosition) = isChecked;
}
});
// set the ClickListener to handle the click event on child item
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
makeToast("clicked");
}
});
return convertView;
}
// method getGroupView is called automatically for each parent item
// Implement this method as per your requirement
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
{
if (convertView == null) {
convertView = inflater.inflate(R.layout.parent_list, null);
}
((CheckedTextView) convertView.findViewById(R.id.textViewGroup)).setText(parentItems.get(groupPosition).getText());
((CheckedTextView) convertView.findViewById(R.id.textViewGroup)).setBackgroundColor(parentItems.get(groupPosition).getColor());
((CheckedTextView) convertView.findViewById(R.id.textViewGroup)).setChecked(isExpanded);
return convertView;
}
#Override
public Object getChild(int groupPosition, int childPosition)
{
return null;
}
#Override
public long getChildId(int groupPosition, int childPosition)
{
return 0;
}
#Override
public int getChildrenCount(int groupPosition)
{
return childItems.get(groupPosition).getText().size();
}
#Override
public Object getGroup(int groupPosition)
{
return null;
}
#Override
public int getGroupCount()
{
return parentItems.size();
}
#Override
public void onGroupCollapsed(int groupPosition)
{
super.onGroupCollapsed(groupPosition);
}
#Override
public void onGroupExpanded(int groupPosition)
{
super.onGroupExpanded(groupPosition);
}
#Override
public long getGroupId(int groupPosition)
{
return 0;
}
#Override
public boolean hasStableIds()
{
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition)
{
return false;
}
}
[Adapter class]
public class CustomExpandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> expandableListTitle;
private HashMap<String, List<FilterList>> expandableListDetail;
private boolean checked;
private int lastClickedPosition;
private List<Boolean> setValueForSeletedFilter;
private String[] keysOfHashmap;
public CustomExpandableListAdapter(Context context, List<String> expandableListTitle,
HashMap<String, List<FilterList>> expandableListDetail, List<Boolean> setValueForSeletedFilter) {
this.context = context;
this.expandableListTitle = expandableListTitle;
this.expandableListDetail = expandableListDetail;
this.setValueForSeletedFilter = setValueForSeletedFilter;
}
#Override
public Object getChild(int listPosition, int expandedListPosition) {
return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
.get(expandedListPosition).getSearchFilterValue();
}
#Override
public long getChildId(int listPosition, int expandedListPosition) {
return expandedListPosition;
}
#Override
public View getChildView(final int listPosition, final int expandedListPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final String expandedListText = (String) getChild(listPosition, expandedListPosition);
if (convertView == null) {
int i = listPosition;
int j = expandedListPosition;
LayoutInflater layoutInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.list_item, null);
TextView expandedListTextView = (TextView) convertView
.findViewById(R.id.expandedListItem);
expandedListTextView.setText(expandedListText);
String s = expandableListTitle.get(listPosition);
final ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_select);
if (setValueForSeletedFilter.get(expandedListPosition) == true) {
imageView.setVisibility(View.VISIBLE);
} else {
imageView.setVisibility(View.GONE);
}
}
return convertView;
}
private void toggleSelection(int i, View v) {
int j = i;
ImageView imageView = (ImageView) v.findViewById(R.id.iv_select);
imageView.setImageResource(R.drawable.ic_review);
}
#Override
public int getChildrenCount(int listPosition) {
return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
.size();
}
#Override
public Object getGroup(int listPosition) {
return this.expandableListTitle.get(listPosition);
}
#Override
public int getGroupCount() {
return this.expandableListTitle.size();
}
#Override
public long getGroupId(int listPosition) {
return listPosition;
}
#Override
public View getGroupView(int listPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String listTitle = (String) getGroup(listPosition);
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater) this.context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.list_group, null);
}
TextView listTitleTextView = (TextView) convertView
.findViewById(R.id.listTitle);
listTitleTextView.setTypeface(null, Typeface.BOLD);
listTitleTextView.setText(listTitle);
return convertView;
}
#Override
public boolean hasStableIds() {
return true;
}
public void setData(){
notifyDataSetChanged();
}
#Override
public boolean isChildSelectable(int listPosition, int expandedListPosition) {
return true;
}
}
[setting values for adapter class and notifying adapter on changing values]
final HashMap> setValueForSeletedFilter = new HashMap<>();
String header = null;
final List booleanList = new ArrayList<>();
final HashMap> stringListHashMap = new HashMap<>();
final List expandableListTitle;
for (int i = 0; i < filtersInfos.size(); i++) {
stringListHashMap.put(filtersInfos.get(i).getFilterHeaderName(), filtersInfos.get(i).getFilterLists());
if (filtersInfos.get(i).getFilterHeaderName().equalsIgnoreCase("Distance")) {
header = filtersInfos.get(i).getFilterHeaderName();
for (int j = 0; j < filtersInfos.get(i).getFilterLists().size(); j++)
booleanList.add(false);
}
}
setValueForSeletedFilter.put(header, booleanList);
expandableListTitle = new ArrayList<String>(stringListHashMap.keySet());
final CustomExpandableListAdapter adapter = new CustomExpandableListAdapter(this, expandableListTitle, stringListHashMap, booleanList);
expandableListView.setAdapter(adapter);
filterDialog.show();
expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
Toast.makeText(getApplicationContext(),
expandableListTitle.get(groupPosition) + " List Expanded.",
Toast.LENGTH_SHORT).show();
}
});
expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(getApplicationContext(),
expandableListTitle.get(groupPosition) + " List Collapsed.",
Toast.LENGTH_SHORT).show();
}
});
final boolean[] checked = {false};
final int[] lastClickedPosition = {0};
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
if (expandableListTitle.get(groupPosition).equalsIgnoreCase("Distance")) {
booleanList.add(childPosition, true);
setValueForSeletedFilter.put(expandableListTitle.get(groupPosition), booleanList);
expandableListView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
return false;
}
});
close.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
filterDialog.dismiss();
}
});
done.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
on the basis of header make list single or multi selection android.
getChildView() example for my case "Single selection"
#Override
public View getChildView(final int i, final int i1, boolean b, View view, ViewGroup viewGroup) {
View v = LayoutInflater.from(context).inflate(R.layout.expandablelv_child, null);
final CheckBox checkBox = v.findViewById(R.id.expandable_lv_child_cb);
RelativeLayout quantityContainer = v.findViewById(R.id.expandable_lv_child_quantity_cont);
final TextView textView = v.findViewById(R.id.expandable_lv_child_quantity_tv);
checkBox.setText(children.get(i).get(i1).getItemName());
double d=Double.parseDouble(children.get(i).get(i1).getMinQty());
int k=(int)d;
textView.setText(String.valueOf(k));
quantityContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
QuantityDialog dialog = new QuantityDialog(context, children.get(i).get(i1).getMinQty(),
children.get(i).get(i1).getMaxQty(), new DialogSelectable() {
#Override
public void onQuantitySelected(String quantity) {
if (group[i].parent == 1 && group[i].child == i1)
textView.setText(quantity);
ExpandableLvAdapter.quantity[i] = quantity;
}
});
dialog.show();
}
});
try {
// if (model.children.get(i).size() < children.get(i).size()) {
try {
model.children.get(i).add(checkBox);
} catch (Exception e) {
ArrayList<CheckBox> temp = new ArrayList<>();
temp.add(checkBox);
model.children.add(temp);
}
//}
} catch (Exception e) {
try {
model.children.get(i).add(checkBox);
} catch (Exception ex) {
ArrayList<CheckBox> temp = new ArrayList<>();
temp.add(checkBox);
model.children.add(temp);
}
}
if (group[i].parent == 1) {
model.children.get(i).get(group[i].child).setEnabled(true);
model.children.get(i).get(group[i].child).setChecked(true);
model.disable(i, children.get(i).get(group[i].child).getItemName());
} else {
model.enable(i);
}
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
group[i].parent = 1;
group[i].child = i1;
model.disable(i, children.get(i).get(i1).getItemName());
selected.add(children.get(i).get(i1));
quantity[i] = children.get(i).get(i1).getMaxQty();
} else {
group[i].parent = 0;
model.enable(i);
}
}
});
return v;
}
Friends,
I am trying to write a application which use checkbox in ExpandableListView, I got a problem here which is maintaining checkbox state of the application, I got the example from here , my problem is maintaining checked state of the checkboxes, whenever I check one of the checkboxes and Expand the List, the checkboxes do not have the checked state where they supposed to have. I have try to maintain by adding ArrayList to store the position of the store and reload the position in getChildView() but still not achieve what I want to do. here is my code
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;
}
}
this is my answer to the this issue, u need to keep a check state for individual child and check on it when the the child is clicked. after some research, this is due to android's view lifecycle causing the view to refresh thus not keeping the state.
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;
}
}
I also have this problem. Finally I found the root cause and the solution. To fix this, instead of setting the checkState for the checkBox, you should set its containing listView's 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;
}
...
}
ExpandableListView with multiselect. Tested on API 4.3 and 4.0.3
This code also correctly handles changing screen orientation. Blocking groups made to work properly with the selected elements through SparseBooleanArray.
I hope this sample code will help :)
Activity
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());
}
Adapter
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 class
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 class
public class YouSubCat implements Serializable {
private static final long serialVersionUID = -1487507723105914936L;
public String name = null, desc = null;
public boolean selected = false;
}
Child row layout
<?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>
Group layout
<?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>
Get selected child items
final SparseBooleanArray checkedItems = list.getCheckedItemPositions();
for (int i = 0; i < checkedItems.size(); i++) {
if(checkedItems.valueAt(i))
data = ((String)list.getItemAtPosition(checkedItems.keyAt(i)));
}
Expandable ListView With Checkbox.
We can get the complete example in github which is maintaining the checkbox state of the expandable list.
Click the link to get Android studio project
https://github.com/bhat-dinesh/ExpandableListViewWithCheckBox
I hope this helps :)