I'm writing filter in Android and want to use BaseExpandableListAdapter with checkboxes. In my situation if the group elements have any child elements, may select group element too. Also all child elements may selected. Offer screenshot: enter image description here
When i open dialog and select neccessary elements, then its selected elements put to text edittext. My problem in this, when i reopen dialog and close/open group elements my selected checkboxes changes. I can't find solution how to remember choices, when reopen dialog.
All my neccessary code offer following:
My entity class:
public class Category implements Listable, Parcelable{
private int id;
private String title;
private String c_date;
private List<Category> sub_categories = new ArrayList<>();
private boolean isChecked;
private int parent;
protected Category(Parcel in) {
id = in.readInt();
title = in.readString();
c_date = in.readString();
sub_categories = in.createTypedArrayList(Category.CREATOR);
isChecked = in.readByte() != 0;
parent = in.readInt();
m_date = in.readString();
}
public static final Creator<Category> CREATOR = new Creator<Category>() {
@Override
public Category createFromParcel(Parcel in) {
return new Category(in);
}
@Override
public Category[] newArray(int size) {
return new Category[size];
}
};
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(id);
parcel.writeString(title);
parcel.writeString(c_date);
parcel.writeTypedList(sub_categories);
parcel.writeByte((byte) (isChecked ? 1 : 0));
parcel.writeInt(parent);
parcel.writeString(m_date);
}
//getters, setters
}
My adapter class:
public class CategoryAdapter extends BaseExpandableListAdapter {
private Context context;
private ArrayList<Category> categories;
private LayoutInflater inflater;
public CategoryAdapter(Context context,
ArrayList<Category> categoryList) {
this.context = context;
this.categories = categoryList;
inflater = LayoutInflater.from(context);
}
public Object getChild(int groupPosition, int childPosition) {
return categories.get(groupPosition).getSub_categories().get(childPosition);
}
public long getChildId(int groupPosition, int childPosition) {
return (long)( groupPosition*1024+childPosition ); // Max 1024 children per group
}
private static class ViewHolder {
private TextView title;
private CheckBox cb;
}
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolder viewHolder;
boolean isChecked = categories.get(groupPosition).getSub_categories().get(childPosition).isChecked();
if (v != null)
viewHolder = (ViewHolder) v.getTag();
else {
v = inflater.inflate(R.layout.category_child_row, parent, false);
viewHolder = new ViewHolder();
viewHolder.title = (TextView)v.findViewById(R.id.title);
viewHolder.cb = (CheckBox)v.findViewById(R.id.check);
viewHolder.cb.setChecked(isChecked);
viewHolder.cb.setOnCheckedChangeListener(new CheckchangeChildListener(groupPosition, childPosition));
v.setTag(viewHolder);
}
final Category c = (Category) getChild( groupPosition, childPosition );
viewHolder.title.setText(c.getTitle());
return v;
}
class CheckchangeChildListener implements CompoundButton.OnCheckedChangeListener {
private int position;
private int childPosition;
public CheckchangeChildListener(int position, int childPosition) {
this.position= position;
this.childPosition = childPosition;
}
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
categories.get(position).getSub_categories().get(childPosition).setChecked(true);
} else {
categories.get(position).getSub_categories().get(childPosition).setChecked(false);
}
}
}
public int getChildrenCount(int groupPosition) {
return categories.get(groupPosition).getSub_categories().size();
}
public Object getGroup(int groupPosition) {
return categories.get( groupPosition );
}
public int getGroupCount() {
return categories.size();
}
public long getGroupId(int groupPosition) {
return (long)( groupPosition*1024 ); // To be consistent with getChildId
}
private static class ViewGroupHolder {
private TextView title;
private CheckBox cb;
private ImageView image;
}
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View v = convertView;
ViewGroupHolder holder;
boolean isChecked = categories.get(groupPosition).isChecked();
if(v != null)
holder = (ViewGroupHolder)v.getTag();
else {
v = inflater.inflate(R.layout.category_parent_row, parent, false);
holder = new ViewGroupHolder();
holder.title = (TextView)v.findViewById(R.id.title);
holder.cb = (CheckBox)v.findViewById(R.id.check);
holder.cb.setChecked(isChecked);
holder.image = (ImageView)v.findViewById(R.id.arrow);
holder.cb.setOnCheckedChangeListener(new CheckchangeGroupListener(groupPosition));
v.setTag(holder);
}
final Category category = (Category)getGroup(groupPosition);
holder.title.setText(category.getTitle());
if(getChildrenCount(groupPosition) == 0){
holder.cb.setVisibility(View.VISIBLE);
holder.image.setVisibility(View.INVISIBLE);
} else {
holder.image.setVisibility(View.VISIBLE);
holder.cb.setVisibility(View.INVISIBLE);
holder.image.setImageResource(isExpanded ? R.drawable.ic_chevron_down : R.drawable.ic_chevron_right);
}
return v;
}
class CheckchangeGroupListener implements CompoundButton.OnCheckedChangeListener {
private int position;
public CheckchangeGroupListener(int position) {
this.position= position;
}
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
categories.get(position).setChecked(true);
} else {
categories.get(position).setChecked(false);
}
}
}
public boolean hasStableIds() {
return true;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public void onGroupCollapsed (int groupPosition) {}
public void onGroupExpanded(int groupPosition) {}
public ArrayList<Category> getSelectedCats(){
ArrayList<Category> checkedCategories = new ArrayList<>();
for(Category c: categories){
if(c.isChecked()) checkedCategories.add(c);
if(!c.getSub_categories().isEmpty()){
for(Category category: c.getSub_categories()) {
if (category.isChecked()) checkedCategories.add(category);
}
}
}
return checkedCategories;
}
}
My custom EditText:
public class CategoryEditText<T extends Listable> extends EditText {
List<T> mItems;
String[] mListableItems;
CharSequence mHint;
OnItemSelectedListener<T> onItemSelectedListener;
DialogFragment newFragment;
public CategoryEditText(Context context) {
super(context);
mHint = getHint();
}
public CategoryEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mHint = getHint();
}
public CategoryEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mHint = getHint();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CategoryEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mHint = getHint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setFocusable(false);
setClickable(true);
}
public void setItems(List<T> items) {
this.mItems = items;
newFragment = CategoryDialogFragment.newInstance((ArrayList<Category>)mItems, this);
this.mListableItems = new String[items.size()];
int i = 0;
for (T item : mItems) {
mListableItems[i++] = item.getLabel();
}
configureOnClickListener();
}
private void configureOnClickListener() {
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Context context = getContext();
FragmentManager fm = ((Activity) context).getFragmentManager();
newFragment.show(fm, "dialog");
}
});
}
public void setOnItemSelectedListener(OnItemSelectedListener<T> onItemSelectedListener) {
this.onItemSelectedListener = onItemSelectedListener;
}
public interface OnItemSelectedListener<T> {
void onItemSelectedListener(T item, int selectedIndex);
}
}
My custom dialogfragment to display list:
public class CategoryDialogFragment extends DialogFragment {
ArrayList<Category> categories;
static EditText editText;
public static CategoryDialogFragment newInstance(ArrayList<Category> categories, EditText customEditText) {
CategoryDialogFragment frag = new CategoryDialogFragment();
Bundle args = new Bundle();
args.putParcelableArrayList("categories", categories);
frag.setArguments(args);
editText = customEditText;
return frag;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
categories = getArguments().getParcelableArrayList("categories");
View v = LayoutInflater.from(getActivity()).inflate(R.layout.select_category_layout, null);
ExpandableListView expandableListView = (ExpandableListView) v.findViewById(R.id.list);
final CategoryAdapter categoryAdapter = new CategoryAdapter(getActivity(), categories);
expandableListView.setAdapter(categoryAdapter);
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.title(R.string.shop_category)
.customView(v, false)
.positiveText(R.string.select)
.negativeText(android.R.string.cancel)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
ArrayList<Category> cats = categoryAdapter.getSelectedCats();
String selectedText = "";
for(int i=0; i<cats.size(); i++){
selectedText += cats.get(i).getTitle();
if(i+1 < cats.size()){
selectedText += " | ";
}
}
editText.setText(selectedText);
materialDialog.dismiss();
}
})
.build();
return dialog;
}
}
I tried to reading on the net about that but I didn`t find how to solve my problem.