Expandable list ExpandableListView does not expand when its height is equal to wrap_content and something is underneath
Here is my link code. When I click on the expandable list view, it does not expand. However, if I increase the height of the list, it expands. Is there a way to dynamically increase the height of a list using code? Can I do this to expand in the middle of my layout. Because if I increase the height, it just adds unnecessary spaces to the collapsed list.
Code:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.pocketcash.pocketcash.HomeActivity">
<Switch
android:id="@+id/detailedCashInfoSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:onClick="cashToggleSwitchClicked"
android:text="Toggle Detailed Cash Info" />
<Button
android:id="@+id/addCashButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/expandableListView2"
android:layout_centerHorizontal="true"
android:onClick="launchAddCash"
android:text="Add cash" />
<Button
android:id="@+id/addExpenditureButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/addCashButton"
android:layout_centerHorizontal="true"
android:layout_marginTop="25dp"
android:onClick="launchAddExpenditure"
android:text="Add expenditure" />
<TextView
android:id="@+id/recentLogsText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/addExpenditureButton"
android:layout_marginTop="50dp"
android:text="Recent Logs:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/logText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/recentLogsText"
android:layout_marginTop="0dp"
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/recentViewAllText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/recentLogsText"
android:layout_marginLeft="10dp"
android:layout_toEndOf="@+id/recentLogsText"
android:layout_toRightOf="@+id/recentLogsText"
android:onClick="recentViewLogClicked"
android:text="(view all)"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/addViewAllText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/addCashButton"
android:layout_centerHorizontal="true"
android:onClick="addViewLogClicked"
android:text="(view logs)"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/expenseViewAllText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/addExpenditureButton"
android:layout_centerHorizontal="true"
android:onClick="expenseViewLogClicked"
android:text="(view logs)"
android:textAppearance="?android:attr/textAppearanceSmall" />
<ImageView
android:id="@+id/userImage"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/detailedCashInfoSwitch"
android:layout_marginTop="34dp"
android:background="@drawable/default_user" />
<TextView
android:id="@+id/nameText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/userImage"
android:layout_marginLeft="25dp"
android:layout_toEndOf="@+id/userImage"
android:layout_toRightOf="@+id/userImage"
android:text="Name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/logoutText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/nameText"
android:layout_alignStart="@+id/nameText"
android:layout_below="@+id/nameText"
android:clickable="true"
android:onClick="logUserOut"
android:text="logout"
android:textAppearance="?android:attr/textAppearanceSmall" />
<ImageButton
android:id="@+id/settingsButton"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignTop="@+id/nameText"
android:layout_marginLeft="25dp"
android:layout_toEndOf="@+id/nameText"
android:layout_toRightOf="@+id/nameText"
android:background="@drawable/settingsicon"
android:onClick="launchSettingsActivity" />
<fragment
android:id="@+id/fragment_currentBalanceInfo"
android:name="com.pocketcash.pocketcash.CurrentBalanceInfoFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/userImage"
android:layout_centerHorizontal="true"
tools:layout="@layout/fragment_current_balance_info" />
<ExpandableListView
android:id="@+id/expandableListView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/fragment_currentBalanceInfo"
android:layout_centerHorizontal="true"
android:clickable="true" />
</RelativeLayout>
</ScrollView>
source to share
After much research on this topic, I could only come to the conclusion that a scrollable object, such as an expandable list, could be declared in a different scrollable form. However, I modified my Java code a bit to solve this issue at runtime.
expListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
int height = 0;
for (int i = 0; i < expListView.getChildCount(); i++) {
height += expListView.getChildAt(i).getMeasuredHeight();
height += expListView.getDividerHeight();
}
expListView.getLayoutParams().height = (height+6)*10;
}
});
// Listview Group collapsed listener
expListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
expListView.getLayoutParams().height = 61;
}
});
This way I dynamically adjusted the height of the widget when it was expanded or collapsed. This is not a reliable method and it is working on hit and trial, so I ended up having to move this widget to a completely new activity. However, it worked flawlessly. But if anyone finds a better answer, please share.
source to share
How Romain Guy (Google Engineer is working on UI Toolkit) Said in his post
By setting width to wrap_content
, you indicate that the ListView will be as wide as the widest of its children. Therefore the ListView has to measure its items and get the items it needs to call getView()
on the adapter. This can happen multiple times depending on the number of layout skips, the behavior of the parent layout, etc.
So, if you set the width or height of the layout of your layout ListView
on wrap_content
, ListView
tries to measure each attached to it an idea - it's definitely not what you want.
Keep in mind: Avoid setting wrap_content for ListViews
or GridViews
or ExpandableListView
at any time, see this Google I / O video on the viewlist world for more details
So, do ExpandableListView
upmatch_parent
source to share
I know the question has already been answered, but I have another solution that might work for more cases: I set the initial height of the list by counting the number of elements and then update that height when the group changes / expands to get the number of children expanded / collapsed group. Here's some sample code:
int item_size = 50; // 50px
int sub_item_size = 40; // 40px
expListView.getLayoutParams().height = item_size*myAdapter.getGroupCount();
expenseListView.setAdapter(myAdapter);
// ListView Group Expand Listener
expenseListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
int nb_children = myAdapter.getChildrenCount(groupPosition);
expenseListView.getLayoutParams().height += sub_item_size*nb_children;
}
});
// Listview Group collapsed listener
expenseListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
int nb_children = myAdapter.getChildrenCount(groupPosition);
expenseListView.getLayoutParams().height -= sub_item_size*nb_children;
}
});
source to share
Usually we cannot use ListView, GridView or ExpandableListView inside Scrollview. If you need this, then you must set a fixed height for your expandable ListView.
private void setListViewHeight(final ExpandableListView listView, final int groupPosition) {
final ExpandableListAdapter listAdapter = (ExpandableListAdapter) listView.getExpandableListAdapter();
int totalHeight = 0;
// be careful with unspecified width measure spec, it will ignore all layout params and even
// screen dimensions, so to get correct height, first get maximum width View can use and
// call measure() this way
final int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.EXACTLY);
for (int i = 0; i < listAdapter.getGroupCount(); i++) {
final View groupItem = listAdapter.getGroupView(i, false, null, listView);
groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += groupItem.getMeasuredHeight();
// count only expanded other groups or the clicked collapsed one
if (((listView.isGroupExpanded(i)) && (i != groupPosition))
|| ((!listView.isGroupExpanded(i)) && (i == groupPosition))) {
for (int j = 0, childrenNumber = listAdapter.getChildrenCount(i); j < childrenNumber; j++) {
final View listItem = listAdapter.getChildView(i, j, j == childrenNumber - 1, null, listView);
listItem.measure(desiredWidth, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
totalHeight += listItem.getMeasuredHeight();
}
}
}
final ViewGroup.LayoutParams params = listView.getLayoutParams();
final int height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
params.height = height;
listView.setLayoutParams(params);
listView.requestLayout();
}
and assign this method to the click of the list group:
expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(final ExpandableListView expandableListView, final View view, final int groupPosition, final long id) {
setListViewHeight(expandableListView, groupPosition);
return false;
}
});
IMPORTANT : while this code should work in most cases, I had some problems where the child list items were TextViews with android:layout_height="wrap_content"
so their height depended on their width, which could be related to this problem: ViewGroup {TextView, ...}. getMeasuredHeight gives wrong value less than real height . Please post a comment if you manage to fix this.
source to share