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;
}
}
Related
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();
Hey guys I am trying to get items on ExpandableListView's setOnGroupClickListener & setOnChildClickListener but not getting it's item.
Here is my code :
Group.java
public class Group {
private String Name;
private ArrayList<Child> Items;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public ArrayList<Child> getItems() {
return Items;
}
public void setItems(ArrayList<Child> items) {
Items = items;
}
}
Child.java
public class Child {
private String Name;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}
ExpandListAdapter.java
public class ExpandListAdapter extends BaseExpandableListAdapter {
private Context context;
private ArrayList<Group> groups;
public ExpandListAdapter(Context context, ArrayList<Group> groups) {
this.context = context;
this.groups = groups;
}
#Override
public int getGroupCount() {
return groups.size();
}
#Override
public int getChildrenCount(int groupPosition) {
ArrayList<Child> chList = groups.get(groupPosition).getItems();
return chList.size();
}
#Override
public Object getGroup(int groupPosition) {
return groups.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
ArrayList<Child> chList = groups.get(groupPosition).getItems();
return chList.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) {
Group group = (Group) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inf = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
convertView = inf.inflate(R.layout.group_item, null);
}
TextView tv = (TextView) convertView.findViewById(R.id.group_name);
tv.setText(group.getName());
return convertView;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
Child child = (Child) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context
.getSystemService(context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.child_item, null);
}
TextView tv = (TextView) convertView.findViewById(R.id.country_name);
tv.setText(child.getName().toString());
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
String url = "http://ec2-52-40-135-171.us-west-2.compute.amazonaws.com/shop-cart/backend/web/api/category";
private ExpandListAdapter ExpAdapter;
private ExpandableListView ExpandList;
ArrayList<Group> list;
ArrayList<Child> ch_list;
Group gru;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ExpandList = (ExpandableListView) findViewById(R.id.exp_list);
list = new ArrayList<Group>();
makejsonobjreq();
ExpandList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {
Toast.makeText(MainActivity.this, list.get(i) + "", Toast.LENGTH_SHORT).show();
return false;
}
});
ExpandList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i1, long l) {
Toast.makeText(MainActivity.this, "" + ExpAdapter.getChild(i, i1), Toast.LENGTH_SHORT).show();
return false;
}
});
}
private void makejsonobjreq() {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.e("RES", String.valueOf(response));
try {
JSONObject jo = response.getJSONObject("data");
Log.e("data RES", jo.toString());
Log.e("dataLENGTH", String.valueOf(jo.length()));
//CHNGE NEEDED ==> REPLACE 2 WITH jo.length();
for (int i = 0; i < 2; i++) {
gru = new Group();
gru.setName(jo.getJSONObject(String.valueOf(i + 1)).getJSONArray("parent").getJSONObject(0).getString("name"));
Log.e("gru", gru.getName());
ch_list = new ArrayList<Child>();
JSONArray ja = jo.getJSONObject(String.valueOf(i + 1)).getJSONArray("child");
Log.e("child ARRAY", String.valueOf(ja));
Log.e("child LENGTH", String.valueOf(ja.length()));
for (int j = 0; j < ja.length(); j++) {
Child ch = new Child();
ch.setName(ja.getJSONObject(j).getString("name"));
ch_list.add(ch);
Log.e("CHILD NAME", "VAL OF J " + j + " " + ja.getJSONObject(j).getString("name"));
}
gru.setItems(ch_list);
list.add(gru);
}
ExpAdapter = new ExpandListAdapter(MainActivity.this, list);
ExpandList.setAdapter(ExpAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(jsonObjectRequest);
}
}
put your item into the view as a tag in getChildView or getGroupView like this:
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
Child child = (Child) getChild(groupPosition, childPosition);
// keep your code
// set item as a tag
convertView.setTag(child);
return convertView;
}
then you can get the item in the callback like
ExpandList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i1, long l) {
// get tag from view, it will be better if your check the object type.
Child child = (Child)view.getTag();
return false;
}
});
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.
The problem is your getView() method. I'd suggest reading up on how to correctly write a list adapter class.
private static class ViewHolder {
private TextView title;
private ChecBbox cb;
}
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolder holder;
boolean isChecked = categories.get(groupPosition).getSub_categories().get(childPosition).isChecked();
if( convertView != null )
viewHolder = (ViewHolder) v.getTag();
else {
v = inflater.inflate(R.layout.category_child_row, parent, false);
viewHolder = new ViewHolder();
holder.title = (TextView)v.findViewById(R.id.title);
holder.cb = (CheckBox)v.findViewById(R.id.check);
holder.cb.setChecked(isChecked);
cb.setOnCheckedChangeListener(new CheckchangeChildListener(groupPosition, childPosition));
v.setTag(viewHolder);
}
final Category c = (Category) getChild( groupPosition, childPosition );
title.setText(c.getTitle());
return v;
}
Checked changed listener:
class CheckchangeGroupListener implements CompoundButton.OnCheckedChangeListener {
private int groupPosition, childPosition;
public CheckchangeGroupListener(int groupPosition, int childPosition) {
this.groupPosition= groupPosition;
this.childPosition = childPosition;
}
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
categories.get(groupPosition).getSub_categories().get(childPosition).setChecked(true);
} else {
categories.get(groupPosition).getSub_categories().get(childPosition).setChecked(false);
}
}
I have a expandableListView and tried to change its childs like that:
((SubItem) adapter.getChild(i+1, 5)).setCount(unreadBox);
adapter.notifyDataSetChanged();
Here is my adapter class:
public class DrawerAdapter extends BaseExpandableListAdapter {
private Context context;
private List<Item> items;
private List<List<SubItem>> subItems;
public DrawerAdapter(Context context, List<Item> items, List<List<SubItem>> subItems) {
this.context = context;
this.items = items;
this.subItems = subItems;
}
#Override
public int getGroupCount() {
return items.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return subItems.get(groupPosition).size();
}
#Override
public Object getGroup(int position) {
return items.get(position);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return subItems.get(groupPosition).get(childPosition);
}
#Override
public long getGroupId(int position) {
return position;
}
#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 view, ViewGroup viewGroup) {
Item item = (Item) getGroup(groupPosition);
if (view == null) {
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.list_drawer_group, null);
}
ImageView iconView = (ImageView) view.findViewById(R.id.icon_view);
if (item.iconDrawableId != null) {
iconView.setImageResource(item.iconDrawableId);
iconView.setVisibility(View.VISIBLE);
} else {
iconView.setVisibility(View.GONE);
}
TextView groupHeader = (TextView) view.findViewById(R.id.group_header);
groupHeader.setText(item.title);
if (item.iconDrawableId != null) {
groupHeader.setPadding(
DimensionHelper.dpToPixels(context, 4.0f), 0,
DimensionHelper.dpToPixels(context, 16.0f), 0);
} else {
groupHeader.setPadding(
DimensionHelper.dpToPixels(context, 16.0f), 0,
DimensionHelper.dpToPixels(context, 16.0f), 0);
}
ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
imageView.setImageResource(isExpanded ? R.drawable.ic_navigation_collapse : R.drawable.ic_navigation_expand);
imageView.setVisibility(getChildrenCount(groupPosition) > 0 ? View.VISIBLE : View.GONE);
return view;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isExpanded, View view, ViewGroup viewGroup) {
SubItem subItem = (SubItem) getChild(groupPosition, childPosition);
if (view == null) {
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.list_drawer_item, null);
}
TextView colorPreView = (TextView) view.findViewById(R.id.colorPreView);
if (subItem.getColor() != -1) {
colorPreView.setBackgroundColor(subItem.getColor());
colorPreView.setVisibility(View.VISIBLE);
} else {
colorPreView.setVisibility(View.GONE);
}
ImageView iconView = (ImageView) view.findViewById(R.id.icon_view);
if (subItem.iconDrawableId != null) {
iconView.setImageResource(subItem.iconDrawableId);
iconView.setVisibility(View.VISIBLE);
} else {
iconView.setVisibility(View.GONE);
}
TextView title = (TextView) view.findViewById(R.id.title_text_view);
title.setText(subItem.title);
if (subItem.iconDrawableId != null) {
title.setPadding(
DimensionHelper.dpToPixels(context, 4.0f), 0,
DimensionHelper.dpToPixels(context, 16.0f), 0);
} else {
title.setPadding(
DimensionHelper.dpToPixels(context, 40.0f), 0,
DimensionHelper.dpToPixels(context, 16.0f), 0);
}
TextView counter = (TextView) view.findViewById(R.id.counter_text_view);
counter.setText(String.valueOf(subItem.count));
counter.setVisibility(subItem.count > 0 ? View.VISIBLE : View.GONE);
return view;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public static class Item {
protected String title;
protected Integer iconDrawableId;
protected Listener listener;
public Item(String title, Integer iconDrawableId, Listener listener) {
this.title = title;
this.iconDrawableId = iconDrawableId;
this.listener = listener;
}
public Listener getListener() {
return listener;
}
public static interface Listener {
public void onClick(FragmentManager fragmentManager);
}
}
public static class SubItem extends Item {
protected long count;
protected int color;
public SubItem(String title, Integer iconDrawableId, long count, int color, Listener listener) {
super(title, iconDrawableId, listener);
this.count = count;
this.color = color;
}
public long getCount() {
return count;
}
public void setCount(long count) {
this.count = count;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
}
}
notifyDataSetChanged() method is not working properly, sometimes getChildView is being called sometimes not,please help in order to fix this issue.
You are changing value to child Item however not setting back inside of Adapter.
SubItem item = ((SubItem) adapter.getChild(i+1, 5)).setCount(unreadBox);
adapter.setChild(i+1,5,item);
adapter.notifyDataSetChanged();
add this in Adapter
#Override
public void setChild(int groupPosition, int childPosition,SubItem item) {
subItems.get(groupPosition).get(childPosition) = item;
}
I have an expandable list view where users can click a button to "save" a record. However, the listviews of my expandable listview seem to populate properly (the titles are different). But when a user "saves" element 1 it also saves elements 4,7,10,...n+3 (I know this because the view is set to invisible once it's saved). If you look below, I think I am recycling elements properly using the setTag() method in my getChildView() method.
I put some logging in my getChildView() for testing whether or not the view is cached is or drawn for the first time. The first two views are drawn and the rest are cached.
So my problem, as stated before is that when someone interacts with an element on the expandablelistview other elements are changed accordingly.
Here is my adapter:
public class SurveyListAdapter extends BaseExpandableListAdapter {
private final SparseArray<Group> groups;
public LayoutInflater inflater;
private Context appContext;
public String TAG = "SurveyListAdapter";
private static SparseArray<SparseArray<Survey>> results = new SparseArray<SparseArray<Survey>>();
//private static SparseArray<ArrayList<Boolean>> rowSubmitted = new SparseArray<ArrayList<Boolean>>();
public SurveyListAdapter(Context context, SparseArray<Group> groups) {
this.appContext = context;
this.groups = groups;
for(int i = 0;i<groups.size();i++) {
Log.d(TAG, "Creating group: " + i);
results.put(i, new SparseArray<Survey>());
}
//inflater = context.getLayoutInflater();
this.inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
}
#Override
public Survey getChild(int groupPosition, int childPosition) {
//Log.d("getChild", "Group: " + groupPosition + "\tChild: " + childPosition);
return this.groups.get(groupPosition).children.get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
//return Long.parseLong(this.groups.get(groupPosition).children.get(childPosition));
return childPosition;
}
public Survey getIdOfChild(int groupPosition, int childPosition) {
return this.groups.get(groupPosition).children.get(childPosition);
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View row = convertView;
SurveyViewHolder svh;
Survey child = getChild(groupPosition, childPosition);
if (row == null) {
row = inflater.inflate(R.layout.list_view_survey_row, parent, false);
svh = new SurveyViewHolder();
svh.title = (TextView) row.findViewById(R.id.tvSurveyTitle);
svh.rg = (RadioGroup) row.findViewById(R.id.radioShared);
svh.interest = (CheckBox) row.findViewById(R.id.checkBoxInterest);
svh.privacy = (CheckBox) row.findViewById(R.id.checkBoxPrivacy);
svh.rating = (RatingBar) row.findViewById(R.id.ratingBar);
svh.submit = (Button) row.findViewById(R.id.btnSubmitRow);
row.setTag(svh);
Log.d(TAG, "Built from scratch");
} else {
Log.d(TAG, "Cached");
svh = (SurveyViewHolder) row.getTag();
}
svh.title.setText(child.getTitle());
svh.children = child.getTitle();
svh.submit.setOnClickListener(new CustomOnClickListener(row, svh, groupPosition, childPosition));
//this.registerClickListeners(groupPosition, childPosition, convertView);
return row;
}
#Override
public int getChildrenCount(int groupPosition) {
return groups.get(groupPosition).children.size();
}
#Override
public Object getGroup(int groupPosition) {
return groups.get(groupPosition);
}
#Override
public int getGroupCount() {
return groups.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 groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.xplist_view_survey_group, null);
}
Group group = (Group) getGroup(groupPosition);
((TextView) convertView).setText(group.string);
//((CheckedTextView) convertView).setChecked(isExpanded);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
public SparseArray<SparseArray<Survey>> getResults() {
return results;
}
public void emptyResults() {
for(int i=0; i<results.size();i++) {
for(int j=0;j<results.get(i).size();j++) {
results.get(i).remove(j);
}
}
}
public class SurveyViewHolder {
public TextView title;
public RadioGroup rg;
public RatingBar rating;
public CheckBox interest;
public CheckBox privacy;
public Button submit;
public String children;
}
public class CustomOnClickListener implements View.OnClickListener {
private View row;
private SurveyViewHolder svh;
private int group;
private int child;
public CustomOnClickListener(View r, SurveyViewHolder s, int g, int c) {
this.row = r;
this.svh = s;
this.group = g;
this.child = c;
}
#Override
public void onClick(View v) {
boolean addIt = false;
try{
if(results.get(this.group).get(this.child, null) == null) {
addIt = true;
}
} catch(NullPointerException e) {
Log.d(TAG, "NPE");
addIt = true;
}
if (addIt) {
if (svh.rg.getCheckedRadioButtonId() > 0 && svh.rating.getRating() > 0) {
Boolean[] reasons = new Boolean[]{false, false, false};
// Hide the view
this.row.setVisibility(View.INVISIBLE);
// Start saving the record
Survey s = new Survey(svh.title.getText().toString());
s.setRating(svh.rating.getRating());
if (svh.privacy.isChecked()) {
reasons[0] = true;
} else if (svh.interest.isChecked()) {
reasons[1] = true;
}
s.setReason(reasons);
results.get(this.group).put(this.child, s);
Toast.makeText(appContext, "Record Saved", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(appContext, "You must give a rating and shared status", Toast.LENGTH_SHORT).show();
}
} else {
Log.d(TAG, "Record already saved");
this.row.setVisibility(View.INVISIBLE);
}
}
}
}
Thank you for any help, I'm really struggling with this problem!
You set visibility to row in CustomOnClickListener and then reuse this invisible View for new items.
Suppose you pressed Save on second item. It is invisible now. Then if you scroll the second item's view would be reused for new item. Let say that it would be the item 5. Of course you see that 5'th item is hidden, because it is the same View as it was for second item.
Try to update visibility of row inside getChildView() in the same place where you update titles.