Himanshu Ingole
Himanshu Ingole

Reputation: 55

How to Measure child expandable list height and width

I am using expandable list view to make 3 - level hierarchy, would like to know how to set internal list height and width. I knew we have onMeasure for this purpose but in my case it not allowing me to capture whole space of parent list view.

may be I am giving wrong value to it, here is the code which is I am using for setting height and width of child expandable list.

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
    {

        widthMeasureSpec = MeasureSpec.makeMeasureSpec(960,MeasureSpec.AT_MOST);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(800,MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

Currently it appearing as follow

<ParentGroup1                >
<ChildParentGroup>
<Child1>
<Child2>
<child3>
<ParentGroup2                >

and it should appear like below.

<ParentGroup1                >
<ChildParentGroup            >
<Child1                      >
<Child2                      >
<child3                      >
<ParentGroup2                >

Please advise/suggest for the same.

Thanks for your time.

Upvotes: 0

Views: 4936

Answers (7)

Angelo Montil
Angelo Montil

Reputation: 17

Adding to muhammadSalem's answer. This is how I solved my problem by calculating the height of expandableListView's children's total height.

 private fun getSubItemTotalHeight(groupPosition: Int): Int {
    val children: Int = mAdapter.getChildrenCount(groupPosition)

    val desiredWidth: Int = View.MeasureSpec.makeMeasureSpec(mExpandableListView.width,
            View.MeasureSpec.UNSPECIFIED)
    var subItemTotalHeight = 0
    repeat(children) {
        val child = mAdapter.getChildView(groupPosition, it, true, null, null)
        child.layoutParams = ViewGroup.LayoutParams(
                desiredWidth, View.MeasureSpec.UNSPECIFIED)
        child.measure(View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
        subItemTotalHeight += child.measuredHeight
    }

    val dividerCount = children - 1
    val dividerTotalCount = (dividerCount * mExpandableListView.dividerHeight).toFloat()
    showToast(mExpandableListView.dividerHeight.toString())
    val totalDividerPixels = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dividerTotalCount,
            resources.displayMetrics
    )
    return subItemTotalHeight + totalDividerPixels.toInt()
}

One thing to note is that if you added a divider height for your expandableListview, you should include the calculations for it. What I did is convert the total divider height which is in dp into pixels and added it into the totalHeight. This solved the clipping issues I encountered.

Then to use it would be just :

    mExpandableListView.setOnGroupExpandListener { groupPosition ->
            mExpandableListView.layoutParams.height += getSubItemTotalHeight(groupPosition)
            mExpandableListView.requestLayout()
        }
        mExpandableListView.setOnGroupCollapseListener { groupPosition ->
            mExpandableListView.layoutParams.height -= getSubItemTotalHeight(groupPosition)
            mExpandableListView.requestLayout()
        }

Upvotes: 0

Pablo
Pablo

Reputation: 261

I know its late, but if anyone has the same issue. You can solve it by creating a Custom ExpandableListView and using "MeasureSpec.EXACTLY":

public class CustomExpListView extends ExpandableListView{
    public CustomExpListView(Context context){
        super(context);
    }
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(960, MeasureSpec.EXACTLY);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(20000, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

Hope this helps to anyone. For me its working.

Upvotes: 0

rogue_shadow
rogue_shadow

Reputation: 105

Simply remove the width code and it should work fine.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    heightMeasureSpec = MeasureSpec.makeMeasureSpec(999999, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

Upvotes: 0

PAD
PAD

Reputation: 2330

I succeeded in some days ago by doing this. It's a little bit more compact and without any additionnal parameter, and it works perfectly.

public static void setExpandableListViewHeightBasedOnChildren(ExpandableListView expandableListView){
    ExpandableNotesListAdapter adapter = (ExpandableNotesListAdapter) expandableListView.getExpandableListAdapter();
    if (adapter == null){
        return;
    }
    int totalHeight = expandableListView.getPaddingTop() + expandableListView.getPaddingBottom();
    for (int i = 0 ; i < adapter.getGroupCount() ; i++){
        View groupItem = adapter.getGroupView(i, false, null, expandableListView);
        groupItem.measure(View.MeasureSpec.UNSPECIFIED,View.MeasureSpec.UNSPECIFIED);
        totalHeight += groupItem.getMeasuredHeight();

        if (expandableListView.isGroupExpanded(i) ){
            for( int j = 0 ; j < adapter.getChildrenCount(i) ; j++) {
                View listItem = adapter.getChildView(i, j, false, null, expandableListView);
                listItem.setLayoutParams(new LayoutParams(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED));
                listItem.measure(View.MeasureSpec.makeMeasureSpec(0,
                        View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                        .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                totalHeight += listItem.getMeasuredHeight();

            }
        }
    }

    ViewGroup.LayoutParams params = expandableListView.getLayoutParams();
    int height = totalHeight + expandableListView.getDividerHeight() * (adapter.getGroupCount() - 1);

    if (height < 10)
        height = 100;
    params.height = height;
    expandableListView.setLayoutParams(params);
    expandableListView.requestLayout();
}

Don't forget to add this when you init your View, set your adapter, etc. :

Functions.setExpandableListViewHeightBasedOnChildren(listView);
listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
    @Override
    public void onGroupExpand(int groupPosition) {
        Functions.setExpandableListViewHeightBasedOnChildren(listView);
    }
});

Upvotes: 1

Mohammed Saleem
Mohammed Saleem

Reputation: 578

use this code to calculate expandable list view dynamically:

    // calculate the height of expandable listView without expanded
      private void setListViewHeight(ExpandableListView expListView) {
    ListAdapter listAdapter = expListView.getAdapter();
    int totalHeight = 0;

    for (int i = 0; i < listAdapter.getCount(); i++) {
        View listItem = listAdapter.getView(i, null, expListView);
        listItem.measure(0, 0);
        totalHeight += listItem.getMeasuredHeight();
        System.out.println("i  " + i);
    }

    ViewGroup.LayoutParams params = expListView.getLayoutParams();
    params.height = totalHeight
            + (expListView.getDividerHeight() * (listAdapter.getCount() - 1));
    System.out.println("params.height =  " + params.height);

    expListView.setLayoutParams(params);
    expListView.requestLayout();
}

// calculate the height of expandable listview dynamically
private void setListViewHeight(ExpandableListView expListView, int group) {

    ExpandableListAdapter listAdapter = expListView
            .getExpandableListAdapter();
    int totalHeight = 0;
    int desiredWidth = MeasureSpec.makeMeasureSpec(expListView.getWidth(),
            MeasureSpec.UNSPECIFIED);
    for (int i = 0; i < listAdapter.getGroupCount(); i++) {
        View groupItem = listAdapter.getGroupView(i, false, null,
                expListView);
        groupItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);

        totalHeight += groupItem.getMeasuredHeight();

        if (((expListView.isGroupExpanded(i)) && (i == group))
                || ((!expListView.isGroupExpanded(i)) && (i == group))) {

            for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {

                View listItem = listAdapter.getChildView(i, j, false, null,
                        expListView);

                Log.e("Count", listAdapter.getChildrenCount(i) + "");

                listItem.setLayoutParams(new ViewGroup.LayoutParams(
                        desiredWidth, MeasureSpec.UNSPECIFIED));
                // listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
                listItem.measure(MeasureSpec.makeMeasureSpec(0,
                        MeasureSpec.UNSPECIFIED), MeasureSpec
                        .makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                totalHeight += listItem.getMeasuredHeight();

                System.out.println("totalHeight" + totalHeight);
                Log.e("TEST", "gshdkfmjfy,");

            }
        }
    }

    ViewGroup.LayoutParams params = expListView.getLayoutParams();
    int height = totalHeight
            + (expListView.getDividerHeight() * (listAdapter
                    .getGroupCount() - 1));

    if (height < 10) {
        height = 100;
    }
    params.height = height;
    expListView.setLayoutParams(params);
    expListView.requestLayout();

}

Upvotes: 2

nullPointer
nullPointer

Reputation: 21

Not sure if you're still looking for an answer, but this is how I did it: pass a reference to the parent view and a height measure (in this case, I used the size of the child list) in the constructor to create the child custom list.

public CustomExpandableList(Context context, View the_parentView, int the_heightMeasure)
{ 
    super(context);
    WIDTH = the_parentView!=null?the_parentView.getWidth():LayoutParams.MATCH_PARENT;
    HEIGHT = the_heightMeasure * 500;
}

EDIT: Or to make the code more consistent, you could pass the width of the parentView and height measure to the constructor instead of passing the parent view itself. CustomExpandableList(Context the_context, int the_width, int the_heightMeasure)

Upvotes: 2

Venkata Krishna
Venkata Krishna

Reputation: 1603

Create one layout xml file for ParentGroup and ChildParentGroup , another layout xml file for Child. Now you are problem is reduced to two level hierarchy. Then In Expandable listview we have Parent view and childview methods to inflate and use the Parent and Child layouts. So in that mehods you can do whatever you want.

Upvotes: 0

Related Questions