Hello,
Last day while at work I encountered an issue such as when I try to implement a expandable listview the override method "@getChildView" is not being called. When I looked around, I found out that the issue is mainly related to the expandable listview being inside a scrollview or any such complex layouts. I fixed the issue after searching through some answers on stack overflow, I have provided the links of the original answer at the end of the post
Response will be of the format
{
"movie_details": [
{
"name": "Fight Club",
"type": "Movie",
"id": 1
},
{
"name": "13 reasons why",
"type": "Series",
"id": 2
},
{
"name": "Dunkirk",
"type": "Movie",
"id": 3
},
{
"name": "Game of thrones",
"type": "Series",
"id": 4
},
{
"name": "Godfather",
"type": "Movie",
"id": 5
}
]
}
We are going to create an expandablelistview on the basis of "Movies" and "Series". We will check for the type and classify the list according to it Let's first create two layouts each for child and parent and we will name them as "child_layout.xml" and "parent_layout.xml"
child_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/txt_movie_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="GodFather"/>
<TextView
android:id="@+id/txt_id"
android:layout_marginTop="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="10"/>
</LinearLayout>
parent_layout.xml <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp" >
<TextView
android:id="@+id/txt_speciality_header"
android:text="Movies"
android:textSize="15sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="25dp"/>
</LinearLayout>
I used POJO classes to create the expected response and used GSON parsing for parse the JSON Object to Java Object. I called the method "setSortedList" and passed the ArrayList along with it. private void setSortedList(DetailsModel movie_details) {
if (movie_details.getMovie_details() == null || movie_details.getMovie_details().size() == 0) {
return;
}
Log.e("movdets", new Gson().toJson(movie_details.getMovie_details()));
List<String> listDataHeader = new ArrayList<>();
listDataHeader.add("Movies");
listDataHeader.add("Series");
HashMap<String, List<MovieDetails>> listDataChild = new HashMap<>();
List<MovieDetails> series = new ArrayList<>();
List<MovieDetails> movies = new ArrayList<>();
for (MovieDetails child : movie_details.getMovie_details()) {
if (child.getType().equals("Movie")) {
movies.add(child);
}
else {
series.add(child);
}
}
listDataChild.put("Movies", movies);
listDataChild.put("Series", series);
Log.e("movdets", new Gson().toJson(movies));
Log.e("serdets", new Gson().toJson(series));
expandableListViewAdapter =
new ExpandableListViewAdapter(MainActivity.this, listDataHeader, listDataChild, movies.size(),
series.size());
expandableListView.setAdapter(expandableListViewAdapter);
expandableListView.expandGroup(0);
expandableListView.expandGroup(1);
}
You can see that , we are classifying the list based on it's type only. If it's a "Movie" type then it will be added to the "Movies" list, if not it will be added to the "Series"list. Also we are creating a constructor of the ExpandableListViewAdapter and passing the context, listDataHeader, listDatachild and size of the both the list along with it. I hope you must have added an ExpandableListView in the main_activity.xml file.Let's create the ExpandableListViewAdapter now.
ExpandableListViewAdapter
public class ExpandableListViewAdapter extends BaseExpandableListAdapter {
private Context mContext;
private List<String> mListDataHeader;
private HashMap<String, List<MovieDetails>> mListDataChild;
private LayoutInflater mLayoutInflater;
private int mMovieSize;
private int mSeriesSize;
public ExpandableListViewAdapter(Context context, List<String> listDataHeader, HashMap<String, List<MovieDetails>> listDataChild, int movie_size, int series_size) {
this.mContext = context;
this.mListDataHeader = listDataHeader;
this.mListDataChild = listDataChild;
this.mMovieSize = movie_size;
this.mSeriesSize = series_size;
if (context != null) {
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
Log.e("child", new Gson().toJson(listDataChild));
}
@Override
public int getGroupCount() {
return mListDataHeader.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return this.mListDataChild.get(this.mListDataHeader.get(groupPosition)).size();
}
@Override
public Object getGroup(int groupPosition) {
return mListDataHeader.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosititon) {
return this.mListDataChild.get(this.mListDataHeader.get(groupPosition)).get(childPosititon);
}
@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) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.parent_layout, parent, false);
}
TextView lblListHeader = (TextView) convertView.findViewById(R.id.txt_speciality_header);
lblListHeader.setTypeface(null, Typeface.BOLD);
if (groupPosition == 0) {
lblListHeader.setText(headerTitle + " (" + mMovieSize + ")");
} else {
lblListHeader.setText(headerTitle + " (" + mSeriesSize + ")");
}
return convertView;
}
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView,
ViewGroup parent) {
final MovieDetails movieDetails = (MovieDetails) getChild(groupPosition, childPosition);
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.child_layout, parent, false);
}
TextView name = (TextView)convertView.findViewById(R.id.txt_movie_name);
TextView id = (TextView)convertView.findViewById(R.id.txt_id);
/* TextView name = ButterKnife.findById(convertView,R.id.txt_movie_name);
TextView id = ButterKnife.findById(convertView,R.id.txt_id);*/
name.setText(movieDetails.getName());
id.setText(String.valueOf(movieDetails.getId()));
return convertView;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
}
Now let's run the app and see what happens. Normally, if your main_activity.xml doesn't contains any scrollview or any other complex layout structure, app will run without any problems. But since it does have a scrollview in it, the override method "getchildview" won't be called. when you debug it properly you can find out that the method isn't called at all.Only the "getGroupView" is called
After some research I found out that, the best and quickest solution for this problem is to write a custom ExpandableListView. We will name it as "ExpandExpandableListView"
ExpandExpandableListView
public class ExpandExpandableListView extends ExpandableListView {
boolean expanded = true;
public ExpandExpandableListView(Context context) {
super(context);
}
public ExpandExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandExpandableListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}else{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
The original stackoverflow answer I tried out. Providing the linkstackoverflow answer
Now change your main_activity.xml like
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.bestdoc.jitha.tvseriesnandmovies.MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.bestdoc.jitha.tvseriesnandmovies.ExpandExpandableListView
android:id="@+id/exp_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</org.bestdoc.jitha.tvseriesnandmovies.ExpandExpandableListView>
</LinearLayout>
</ScrollView>
Now run the app again and it'll work without any bugs this time Complete project is available on GitHub
Go to github
Comments
Post a Comment