I am writing an Android application that is utilizing the ExpandableListView feature, and for some reason, I can't seem to get the view to populate. I was originally using a regular ListView, one which populated with the correct information. I then refactored the code to utilize the ExpandableListView. Here are all relevant snippets from my project:
SeasonsFragment.java (Which is called properly in MainActivity)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
ArrayList<Season> seasons = ((App)getActivity().getApplication()).getSeasonsList();
ArrayList<RowItem> rowItems = new ArrayList<>();
for (int i = 0; i < seasons.size(); i++) {
RowItem items = new RowItem(seasons.get(i));
rowItems.add(items);
}
CustomAdapter adapter = new CustomAdapter(getActivity(), rowItems);
View rootView = inflater.inflate(R.layout.seasons_fragment, container, false);
ExpandableListView list_view = (ExpandableListView) rootView.findViewById(R.id.list);
list_view.setAdapter(adapter);
return inflater.inflate(R.layout.seasons_fragment, container, false);
}
CustomAdapter.java
public class CustomAdapter extends BaseExpandableListAdapter {
Context context;
List<RowItem> rowItem;
private HashMap<String, List<Sport>> listDataChildren = new HashMap<>();
public CustomAdapter(Context context, List<RowItem> rowItem) {
Log.i("Custom Adapter", "Created");
this.context = context;
this.rowItem = rowItem;
for (RowItem item : rowItem){
Season season = item.getSeason();
listDataChildren.put(item.getText(), season.getSports());
}
}
#Override
public int getGroupCount() {
return rowItem.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return listDataChildren.get(rowItem.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return rowItem.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return listDataChildren.get(rowItem.get(groupPosition)).get(childPosition);
}
#Override
public long getGroupId(int groupPosition) {
Log.i("Group ID", "Getting group ID");
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) {
Log.i("Group View", "Group view called");
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.row_item, null);
}
final RowItem row_pos = rowItem.get(groupPosition);
TextView txtTitle = (TextView) convertView.findViewById(R.id.title);
txtTitle.setText(row_pos.getText());
Button button = (Button) convertView.findViewById(R.id.button); //TODO: Check memory for subscription status
if (row_pos.isSubscribed()){
row_pos.setSubscribed(false);
button.setBackgroundResource(R.drawable.checkmark3);
} else {
row_pos.setSubscribed(true);
button.setBackgroundResource(R.drawable.ic_add_black_24dp);
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {/*
if (item.isSubscribed()){
item.setSubscribed(false); //TODO: This isn't working properly.
v.setBackgroundResource(R.drawable.checkmark3);
} else {
item.setSubscribed(true);
v.setBackgroundResource(R.drawable.ic_add_black_24dp);
}*/
}
});
return convertView;
}
#Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_item, null);
}
TextView txtListChild = (TextView) convertView
.findViewById(R.id.lblListItem);
txtListChild.setText("TEST");
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
}
All Layout XMLs were inflated properly in the ListView, but nothing is inflating in the ExpandableListView. The method getGroupView isn't even being called. Any help would be appreciated.
Change
return inflater.inflate(R.layout.seasons_fragment, container, false);
to
return rootView;
Related
I am using Exapandable listview inside a fragment,i am passing 8 values but it is showing only 6 values and that too the exapnadable listview is not scrolling.the same if i put it in activity..everything works fine.but when i use within fragment it is showing error.can anyone tell me how to solve it...here is my code
public class GroupsFragment extends Fragment {
View groupview;
List<String> tdp, congress, ysrcp, bjp;
ExpandableListView expandableListView;
HashMap<String, ArrayList<GroupModel>> expandableListDetail;
ArrayList<GroupModel> contacts;
List<String> expandableListTitle;
ExpandableListAdapter expandableListAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the dailog_layout for this fragment
groupview = inflater.inflate(R.layout.contacts_expandable_list, container, false);
expandableListView = groupview.findViewById(R.id.expanded_list_view_contacts);
contacts = new ArrayList<>();
return groupview;
}
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
expandableListDetail = new HashMap<String, ArrayList<GroupModel>>();
showContactsList();
}
#SuppressLint("ClickableViewAccessibility")
private void showContactsList() {
getExpandableListItems();
expandableListTitle = new ArrayList<String>(expandableListDetail.keySet());
expandableListAdapter = new CustomContactsExapandableListAdapter(getActivity(), expandableListTitle, expandableListDetail);
expandableListView.setAdapter(expandableListAdapter);
}
private HashMap<String, ArrayList<GroupModel>> getExpandableListItems() {
contacts.add(new GroupModel("gopi", "Officer", "9999999999", "abcd0"));
expandableListDetail.put("TDP", contacts);
expandableListDetail.put("YSRCP", contacts);
expandableListDetail.put("Congress", contacts);
expandableListDetail.put("BJP", contacts);
expandableListDetail.put("ABC", contacts);
expandableListDetail.put("CDE", contacts);
expandableListDetail.put("DEF", contacts);
expandableListDetail.put("FED", contacts);
return expandableListDetail;
}
}
and here is the adapter
public class CustomContactsExapandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> expandableListTitle;
private HashMap<String, ArrayList<GroupModel>> expandableListDetail;
public CustomContactsExapandableListAdapter(Context context, List<String> expandableListTitle,
HashMap<String, ArrayList<GroupModel>> expandableListDetail) {
this.context = context;
this.expandableListTitle = expandableListTitle;
this.expandableListDetail = expandableListDetail;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return this.expandableListDetail.get(this.expandableListTitle.get(groupPosition))
.get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
Log.i("test", "the value in exapandable is " + getChild(groupPosition, childPosition));
final GroupModel expandedListText = (GroupModel) getChild(groupPosition, childPosition);
Log.i("test", "the text is " + expandedListText.getName()+ " "+ expandedListText.getDesignation() + " " +expandedListText.getMobile() );
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.single_contact, null);
}
TextView expandedListTextViewName = (TextView) convertView
.findViewById(R.id.contact_name);
TextView expandedListTextViewMobile = (TextView) convertView
.findViewById(R.id.contact_mobile_num);
expandedListTextViewMobile.setText(expandedListText.getDesignation());
expandedListTextViewName.setText(expandedListText.getName());
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return this.expandableListDetail.get(this.expandableListTitle.get(groupPosition))
.size();
}
#Override
public Object getGroup(int groupPosition) {
return this.expandableListTitle.get(groupPosition);
}
#Override
public int getGroupCount() {
Log.i("test", "the value in exapandable group is " + expandableListTitle.size());
return expandableListTitle.size();
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String listTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater) this.context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.single_party, null);
}
TextView listTitleTextView = (TextView) convertView
.findViewById(R.id.party_name);
ImageView imageView=convertView.findViewById(R.id.party_expandable_image);
if(isExpanded){
imageView.setImageResource(R.drawable.minus_icon_contacts);
}
else {
imageView.setImageResource(R.drawable.plus_icon_contacts);
}
listTitleTextView.setTypeface(null, Typeface.BOLD);
listTitleTextView.setText(listTitle);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
I have an expandable list view. In the child item of that is a gridview. Inside gridview there are custom checkboxes.
Now the problem is when I check a checkbox and scroll down, or even close the parent view, the check is gone.
Something like this:
Screen checked before scroll:
Screen checked after scroll:
Here is my ExpandableListView Adapter:
public class CreateProfileExpandableAdapter extends BaseExpandableListAdapter {
ArrayList<CreateProfileFecetsHeaderModel> al;
Activity activity;
public CreateProfileExpandableAdapter(Activity activity, ArrayList<CreateProfileFecetsHeaderModel> al) {
this.activity = activity;
this.al = al;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return al.get(groupPosition).getChildren();
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return al.get(groupPosition).hashCode();
}
#Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.create_profile_child, parent, false);
}
ExpandableHeightGridView gridViewChildren = (ExpandableHeightGridView) v.findViewById(R.id.gridViewChildren);
gridViewChildren.setExpanded(true);
CreateProfileChildAdapter createProfileChildAdapter = new CreateProfileChildAdapter(activity, al.get(groupPosition).getChildren());
gridViewChildren.setAdapter(createProfileChildAdapter);
return v;
}
#Override
public int getChildrenCount(int groupPosition) {
return 1;
}
#Override
public Object getGroup(int groupPosition) {
return al.get(groupPosition);
}
#Override
public int getGroupCount() {
return al.size();
}
#Override
public long getGroupId(int groupPosition) {
return al.get(groupPosition).hashCode();
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.create_profile_group, parent, false);
}
TextView textViewGroup = (TextView) v.findViewById(R.id.textViewGroup);
textViewGroup.setText(al.get(groupPosition).getText());
return v;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
Gridview Adapter:
public class CreateProfileChildAdapter extends BaseAdapter {
Activity activity;
ArrayList<CreateProfileFecetsChildModel> al;
int index = -1;
public CreateProfileChildAdapter(Activity activity, ArrayList<CreateProfileFecetsChildModel> al) {
// TODO Auto-generated constructor stub
this.activity = activity;
this.al = al;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return al.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return al.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
private static class ViewHolder {
CheckBox checkBoxChild;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
final ViewHolder viewHolder;
final int pos = position;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(activity);
convertView = inflater.inflate(R.layout.create_profile_grid_child, parent, false);
viewHolder = new ViewHolder();
viewHolder.checkBoxChild = (CheckBox) convertView.findViewById(R.id.checkBoxChild);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.checkBoxChild.setText(al.get(position).getTitle());
viewHolder.checkBoxChild.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
viewHolder.checkBoxChild.setTextColor(activity.getResources().getColor(R.color.white));
} else {
viewHolder.checkBoxChild.setTextColor(activity.getResources().getColor(R.color.black));
}
}
});
return convertView;
}
}
The problem is that the Views get recycled without having their state reset. Imagine displaying 20 items on a screen which only shows four items at once, meaning that the GridViewAdapter uses four, maybe five views. Those views take turns displaying your item when scrolling trough the list:
Solution:
You have to store everything about your view's state (in your case: what is marked as checked) in your Adapter's child list entries of the type CreateProfileFecetsHeaderModel.
In your Adapter's getChildView() fetch the checked state from your Adapter's children using the position and set the holder's CheckBox accordingly.
As it is Expandable adapter, u need to know the groupid,selectedchild,id.
try as below...
#Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final Pair<Long, Long> tag = new Pair<Long, Long>(
getGroupId(groupPosition),
getChildId(groupPosition, childPosition));
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_countryoforigin, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.checkBox.setTag(tag);
viewHolder.checkBox.setChecked(mCheckedItems.contains(tag));
viewHolder.textview.setText((CharSequence) getText(groupPosition, childPosition));
viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final CheckBox cb = (CheckBox) v;
final Pair<Long, Long> tag = (Pair<Long, Long>) v.getTag();
if (cb.isChecked()) {
mCheckedItems.add(tag);
} else {
mCheckedItems.remove(tag);
}
}
});
return convertView;
}
public Set<Pair<Long, Long>> getCheckedItems() {
return mCheckedItems;
}
u can call getcheckitems .....
This is my expandlable list adapter call
TableOfContentsAdapter adapter = new TableOfContentsAdapter(TableOfContentsActivity.this,toCList);
mExpandableListViewTOC.setAdapter(adapter);
And this is my adapter implementation
class TableOfContentsAdapter extends BaseExpandableListAdapter {
private Context context;
private List<TOCLink> tocLinks;
public TableOfContentsAdapter(Context context, List<TOCLink> tocLinks) {
this.context = context;
this.tocLinks = tocLinks;
}
#Override
public int getChildrenCount(int groupPosition) {
return tocLinks.get(groupPosition).getTocLinks().size();
}
#Override
public Object getGroup(int groupPosition) {
return tocLinks.get(groupPosition);
}
#Override
public int getGroupCount() {
return tocLinks.size();
}
#Override
public long getGroupId(int groupPosition) {
return (long) (groupPosition * 1024);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
List<TOCLink> childTocLinks = tocLinks.get(groupPosition).getTocLinks();
return childTocLinks.get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return (long) (groupPosition * 1024 + childPosition);
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
#Override
public View getGroupView(int groupPosition, boolean b, View convertView, ViewGroup viewGroup) {
TOCLink tocLink = (TOCLink) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_header, null);
}
TextView groupHeader = (TextView) convertView.findViewById(R.id.header);
groupHeader.setText(tocLink.getSectionTitle());
return convertView;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean b, View convertView, ViewGroup viewGroup) {
TOCLink tocLink = (TOCLink) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_item, null);
}
TextView childItem = (TextView) convertView.findViewById(R.id.item);
childItem.setText(tocLink.getSectionTitle());
/*TOCLink tocLink1 = tocLinks.get(groupPosition).getTocLinks().get(childPosition);
if (tocLink1.getTocLinks().size() > 0) {
new TableOfContentsAdapter(context, tocLink1.getTocLinks());
}*/
return convertView;
}
}
I want to implement multilevel expandable list view with single adapter. Problem here is i'm able to go to level 1 but not further.
How can resolve this problem?
try to implement in your project: https://github.com/defacto133/MultiLevelExpandableIndentableListView
So I've got a mobile app that loads several objects from the file system, then sorts them by ID, then adds them as categories to an ExpandableListView. However, although the items remain sorted correctly in the Object[] array, the ExpandableListView changes the order seemingly randomly.
In this screenshot, the events should be ordered as follows:
An event Event ID:4
Event 4 Event ID:3
Event 3 Event ID:2
Event 2 Event ID:1
Event 1 Event ID:0
The array is sorted correctly, but when added to the ExpandableListView, the order is randomized.
Here is the code for my EventsListViewAdapter:
public class EventsAdapter extends BaseExpandableListAdapter {
private Context context;
private HashMap<String, List<String>> Events_Category;
private List<String> Events_List;
public EventsAdapter(Context context, HashMap<String, List<String>> Movies_Category, List<String> Movies_List) {
this.context = context;
this.Events_Category = Movies_Category;
this.Events_List = Movies_List;
}
#Override
public int getGroupCount() {
return Events_List.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return Events_Category.get(Events_List.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return Events_List.get(groupPosition);
}
#Override
public Object getChild(int parentPosition, int childPosition) {
return Events_Category.get(Events_List.get(parentPosition)).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) {
String group_title = (String) getGroup(groupPosition);
if(convertView == null) {
LayoutInflater inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflator.inflate(com.cpjd.roblu.R.layout.parent_layout, parent, false);
}
TextView parent_textview = (TextView) convertView.findViewById(com.cpjd.roblu.R.id.parent_txt);
parent_textview.setTypeface(null, Typeface.BOLD);
if(Text.getAPI() > 21) {
parent_textview.setTextColor(Color.parseColor("#FFFFFF"));
} else {
parent_textview.setTextColor(Color.parseColor("#2C3539"));
}
parent_textview.setText(group_title);
return convertView;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parentView) {
String child_title = (String)getChild(groupPosition, childPosition);
if(convertView == null) {
LayoutInflater inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflator.inflate(com.cpjd.roblu.R.layout.child_layout, parentView, false);
}
TextView child_textview = (TextView) convertView.findViewById(com.cpjd.roblu.R.id.child_txt);
child_textview.setText(child_title);
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
i want to create groups and childs in expandable listview from json in android?.how to add the json data to expandable listview group and child item
You can use custom adapter class to create expandable list view. Create a new class file called ExpandableListAdapter.java and extend this from BaseExpandableListAdapter. This class provides required methods to render such listview.
public class ExpandableListAdapter extends BaseExpandableListAdapter {
private Context _context;
private List<String> _listDataHeader; // header titles
// child data in format of header title, child title
private HashMap<String, List<String>> _listDataChild;
public ExpandableListAdapter(Context context, List<String> listDataHeader,
HashMap<String, List<String>> listChildData) {
this._context = context;
this._listDataHeader = listDataHeader;
this._listDataChild = listChildData;
}
#Override
public Object getChild(int groupPosition, int childPosititon) {
return this._listDataChild.get(this._listDataHeader.get(groupPosition))
.get(childPosititon);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final String childText = (String) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.list_item, null);
}
TextView txtListChild = (TextView) convertView
.findViewById(R.id.lblListItem);
txtListChild.setText(childText);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return this._listDataChild.get(this._listDataHeader.get(groupPosition))
.size();
}
#Override
public Object getGroup(int groupPosition) {
return this._listDataHeader.get(groupPosition);
}
#Override
public int getGroupCount() {
return this._listDataHeader.size();
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.list_group, null);
}
TextView lblListHeader = (TextView) convertView
.findViewById(R.id.lblListHeader);
lblListHeader.setTypeface(null, Typeface.BOLD);
lblListHeader.setText(headerTitle);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
Follow this link: http://www.androidhive.info/2013/07/android-expandable-list-view-tutorial/