title: ExpandableListView dynamic child height
body: <p>I have a <code>ExpandableListView</code> which is inside an <code>LinearLayout</code> as container and set by using <code>CustomAdapter</code>.<br>
  For its children, I'm using <code>onGroupClick()</code> method to send an request to specific service and getting result as String, then filling child list of clicked group item.  </p>
  
  <p><strong>The Problem is</strong> since I can't get the updated height (after service response has set to text view of child view's text view) the linearlayout container height doesn't increase the way it should. And it also creates a scrolling problem.</p>
  
  <p>Though list child item xml is <code>WRAP_CONTENT</code> as below:  </p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/root"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:minHeight="@dimen/rowHeight"
  android:background="@color/colorLightYellow"&gt;
  
  &lt;TextView
      android:id="@+id/tvTitle"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_centerVertical="true"
      android:layout_marginLeft="@dimen/marginGeneral"
      android:layout_toLeftOf="@+id/tvCount"
      android:gravity="center_vertical"
      android:paddingBottom="@dimen/marginGeneral"
      android:paddingTop="@dimen/marginGeneral"
      android:text="tvTitle"
      android:textColor="@color/colorGray"
      android:textSize="@dimen/fontSizeNormal" /&gt;
  ...
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p>So the code part is little long stay with me:</p>
  
  <pre><code>@Override
  public boolean onGroupClick(ExpandableListView parent, View v, final int groupPosition, long id) {
      Map&lt;Item, List&lt;ItemDetail&gt;&gt; childList = detailExpandableAdapter.getChildList();
      final Item item = detailExpandableAdapter.getGroup(groupPosition);
      if (childList.get(item).size() == 0) {
          startProgressDialog();
  
          GlobalApplication.getService().getItemDetails(Session.getCurrent().getSessionId(), getItem.item.itemNo, item.name, new ServiceCallback&lt;GetItemDetails&gt;() {
              @Override
              public void onSuccess(GetItemDetails response) {
                  stopProgressDialog();
  
                  List&lt;ItemDetail&gt; itemDetailList = null;
  
                  if (GetItemDetails.isSuccess(response)) {
                      itemDetailList = response.getItemDetailList();
                  } else {
                      itemDetail itemDetail = new ItemDetail();
                      itemDetail.resultDesc = response.getResult().getResultDesc();
  
                      if (StringUtils.isNullOrWhitespace(itemDetail.resultDesc)) {
                          itemDetail.resultDesc = Result.getGeneralFailResult().getResultDesc();
                      }
  
                      itemDetailList = new ArrayList&lt;ItemDetail&gt;();
                      itemDetailList.add(itemDetail);
                  }
  
                  if (itemDetailList != null) {
                      Map&lt;Item, List&lt;ItemDetail&gt;&gt; childList = detailExpandableAdapter.getChildList();
  
                      if (childList.containsKey(item)) {
                          childList.remove(item);
                      }
                      childList.put(item, itemDetailList);
  
                      detailExpandableAdapter.setChildList(childList);
                      detailExpandableAdapter.notifyDataSetChanged();
                      detailExpandableAdapter.notifyDataSetInvalidated();
  
                      listViewLastItems.expandGroup(groupPosition);
                  }
              }
  
              @Override
              public void onFail() {
                  stopProgressDialog();
              }
          });
  
          return false;
      }
  
      return false;
  }
  
  @Override
  public void onGroupExpand(int groupPosition) {
      setExpandableListViewHeightStable(listViewLastItems, llListViewItemDetailContainer);
      if (lastExpanded != -1 &amp;&amp; groupPosition != lastExpanded)
          listViewItems.collapseGroup(lastExpanded);
      lastExpanded = groupPosition;
  }
  
  public void setExpandableListViewHeight(ExpandableListView expandableListView, LinearLayout linearLayoutParent){
      try {
          ExpandableListAdapter expandableListAdapter = expandableListView.getExpandableListAdapter();
  
          int totalHeight = 0;
          int desiredWidth = View.MeasureSpec.makeMeasureSpec(expandableListView.getWidth(), View.MeasureSpec.UNSPECIFIED);
  
          for (int i = 0; i &lt; expandableListAdapter.getGroupCount(); i++) {
              View groupItem = expandableListAdapter.getGroupView(i, false, null, expandableListView);
              groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
  
              //Logger.debug("recalculateExpandableListViewHeight listItem:"+groupItem.getMeasuredHeight());
              totalHeight += groupItem.getMeasuredHeight();
  
              if (expandableListView.isGroupExpanded(i)){
                  for (int j = 0; j &lt; expandableListAdapter.getChildrenCount(i); j++) {
                      View listItemChild = expandableListAdapter.getChildView(i, j, false, null, expandableListView);
  
                      listItemChild.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, View.MeasureSpec.UNSPECIFIED));
                      listItemChild.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
  
                      Logger.debug("recalculateExpandableListViewHeight listItemChild:" + listItemChild.getMeasuredHeight());
                      totalHeight += listItemChild.getMeasuredHeight();
                  }
              }
          }
  
          linearLayoutParent.getLayoutParams().height = totalHeight + (expandableListAdapter.getGroupCount() * expandableListView.getDividerHeight());
          linearLayoutParent.requestLayout();
      } catch (Exception e) {
          Logger.printStackTrace(e);
      }
  }  
  </code></pre>
  
  <p>Update: this is the linear layout I use as container  </p>
  
  <pre><code>&lt;LinearLayout
                  android:id="@+id/llListViewItemContainer"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_below="@+id/tvItemDueDate"
                  android:layout_marginTop="@dimen/marginGeneral"
                  android:orientation="vertical"/&gt;
  </code></pre>
  
  <p>Update 2: I'm adding ExpandableListView to LinearLayout dynamically.</p>
  
  <pre><code>listViewItems = new ExpandableListView(getContext());
  listViewItems.setScrollContainer(false);
  listViewItems.setDivider(new ColorDrawable(getResources().getColor(R.color.colorLightGray)));
  listViewItems.setDividerHeight(UIHelper.convertDptoPixels(1));
  listViewItems.setGroupIndicator(null);
  listViewItems.setOnGroupClickListener(this);
  listViewItems.setOnGroupExpandListener(this);
  listViewItems.setOnGroupCollapseListener(this);
  //generate empty child list
  Map&lt;Item, List&lt;ItemDetail&gt;&gt; childMap = new HashMap&lt;&gt;();
  for (Item item : getItems.getItemList()) {
      childMap.put(item, new ArrayList&lt;ItemDetail&gt;());
                  }
  detailExpandableAdapter = new detailExpandableAdapter(getActivity(), getItems.getItemList(), childMap);
  listViewItems.setAdapter(detailExpandableAdapterF);
  listViewItems.removeAllViews();
  listViewItems.addView(listViewLastItems);
  UIHelper.setExpandableListViewHeightStable(listViewItems, llListViewDetailContainer);
  </code></pre>