21

I have an ExpandableListView inside a NestedScrollView (yes I know, it is not good to have a scrolling view inside another scrolling view but I don't know what else to do, please do tell me if anybody knows a better approach).

The size of the content in NestedScrollView is still within the screen so it won't scroll, but when ExpandableListView is expanded, the content will leak outside the screen but the NestedScrollView still won't scroll.. Why is this so?

Here's my NestedScrollView layout :

<NestedScrollView>
    <LinearLayout>
        <LinearLayout></LinearLayout>
        ... // About 3 of the LinearLayouts
        <ExpandableListView/>
    </LinearLayout>
</NestedScrollView>
Kevin Murvie
  • 2,240
  • 1
  • 18
  • 38
  • 1
    refer this link http://thedeveloperworldisyours.com/android/expandable-listview-inside-scrollview/#sthash.6gtbdQ0F.dpbs – anonymous Jun 03 '16 at 04:32

5 Answers5

76

You can use NonScrollExpandableListView you can achieve non-scroll property of any Lisview or GridView or ExpandableListView by overriding following method.

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
            Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
    ViewGroup.LayoutParams params = getLayoutParams();
    params.height = getMeasuredHeight();
} 

So for using NonScrollExpandableListView you need to make one custom class.

public class NonScrollExpandableListView extends ExpandableListView {

    public NonScrollExpandableListView(Context context) {
        super(context);
    }

    public NonScrollExpandableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public NonScrollExpandableListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
        ViewGroup.LayoutParams params = getLayoutParams();
        params.height = getMeasuredHeight();
    }
}

And use it like.

<com.example.extraclasses.NonScrollExpandableListView 

    android:layout_width="match_parent"
    android:layout_height="wrap_content" /> 

Happy coding.

V-rund Puro-hit
  • 5,270
  • 8
  • 27
  • 48
  • 1
    Will this cause performance issue?? It worked btw but I'm concerned about the performance issue (had NestedScrollview parenting RecyclerView and oh damn, the memory usage.......) – Kevin Murvie Jun 03 '16 at 11:12
  • Not at all. infect it is recommended to use this in cases like yours. – V-rund Puro-hit Jun 03 '16 at 11:17
  • It worked well, but can I just use expandableListView.onMeasure() and not make new class? I am still new at making those kind of custom classes.. Oh and btw it is "in fact" not "infect" lol – Kevin Murvie Jun 03 '16 at 11:26
  • hahah.. I'm bad at spellings.. That is me.. anyway.. you have to make separate class for that.. you can't use it that ways.. – V-rund Puro-hit Jun 03 '16 at 11:30
  • Haha but you're good at coding tho so it's fine :D Oh I see, why is that so? Any reference regarding this matter? – Kevin Murvie Jun 03 '16 at 11:31
  • it is `override` method of `view` class. you can use it only if you are extending any view. and if you see I have done coding inside `onMeasure()`. so if you use it like you mentioned it will take default scroll. and won't give desire result. – V-rund Puro-hit Jun 03 '16 at 11:51
  • OH! How stupid am I, it is an override so the coding of course is different from the source, nevermind what I said, I went stupid there, thanks for the info! :D – Kevin Murvie Jun 04 '16 at 06:39
  • how to setselectedgroup in expandablelistview??? As it is not scrolling when the group is expanded. – Rishabh Srivastava Jul 14 '16 at 10:41
  • @RishabhSrivastava can you elaborate your problem more? – V-rund Puro-hit Jul 14 '16 at 12:41
  • @vrundpurohit suppose there are 10 parent groups. And I want click on 8th, so I want the expandablelistview to scroll and show all its child which is not happening.Otherwise this solution is awesome. – Rishabh Srivastava Jul 15 '16 at 05:50
  • have you tried warping `NonScrollExpandableListView` inside `ScrollView`? – V-rund Puro-hit Jul 15 '16 at 05:53
  • if you did that you probably able to do that. are you using `ScrollView` or 'NestedScrollView'? – V-rund Puro-hit Jul 15 '16 at 06:01
  • 1
    Thank you it is working fine, i have tried so many thing i wanted to avoid adding header or footer .you give me perfect solution for it . – Farhana Naaz Ansari Jun 28 '17 at 10:08
  • Thanks Worked For me. will it work with ListView and Recycler View Too? – VJ Vishal Jogiya Aug 22 '17 at 08:04
  • Yes for `ListVIew` and i don't Recommend for `RecyclerView` – V-rund Puro-hit Aug 22 '17 at 08:05
  • Thanks.Its Working fine.Appreciated! – Ronak Gadhia Aug 22 '17 at 13:46
  • 1
    Put that in your boomstick and shoot it. Boom! It worked! – tango whiskey double Nov 17 '17 at 18:22
  • wow..wow..what a surprise seriously thank u so much buddy..i got struck in 4 days ..ur great. – S HemaNandhini Jan 04 '18 at 06:44
  • How can I animate view while it expand using NonScrollExpandableListView? – Nik Apr 24 '18 at 10:09
  • thanks a lot! But in my case I have a coordinatorlayout and inside it is my nestedscrollview and inside that is my expandablelistview so, what's happening is that my expandablelistview isn't expanding to the fullest unless the keyboard opens, which is weird – amateur programmer Sep 18 '18 at 22:59
  • Thanks Alot Mate. – Hashir Saeed Nov 08 '18 at 14:48
  • @V-rundPuro-hit How to do the same for ListView instead of ExpandableListView??Please help? – KJEjava48 Jul 11 '19 at 07:35
  • @V-rundPuro-hit for me it worked only after i changed Integer.MAX_VALUE >> 2 to Integer.MAX_VALUE >> 21 . Why its so? Also it work's with ScrollView not with NestedScrollView. – KJEjava48 Jul 12 '19 at 06:08
  • @V-rundPuro-hit Seems like this will not work correctly for 3 level or 4 level ExpandableListview. Any help ?? – KJEjava48 Jul 26 '19 at 14:01
  • Tried this solution to add expandable list view and recycler view to nested scrollview. Works fine, to be able to scroll both lists as one, but when you tap on a expandable list view group, when child expands, it doesn't scroll to the child content. – prakash Nov 21 '19 at 12:59
  • @V-rundPuro-hit I have used the example which you have shared here and I have found that some view are not being Gone or Visible. I have a button in ChildView, where If I click I want some layout or Views to be Gone and some Visible, When I debug it I runs the code and even goes into those line but the action of the Code is not being executed. – Athos Tokbi Aug 28 '20 at 16:22
  • Can I know why is that happening!! I know its an old post but Please I am looking forward to your answer. – Athos Tokbi Aug 28 '20 at 16:23
  • @AthosTokbi it totally depends on how are you managing view's visibility. i guess it has nothing to do with this widget. – V-rund Puro-hit Aug 29 '20 at 06:48
  • @V-rundPuro-hit Okay. However, if you don't mind looking into my query as a beginer I would really appreciate it. Here is the [Link](https://stackoverflow.com/questions/63639352/question-regarding-the-expandablelistview-childviews-button-clicklistener?noredirect=1#comment112537467_63639352) – Athos Tokbi Aug 29 '20 at 06:57
7

Add android:nestedScrollingEnabled="true" to your ExpandalbleListView layout.

Paweł B
  • 99
  • 1
  • 2
3

Use this method this will calculate the ExpendableListSize at run time.

 private void setListViewHeight(ExpandableListView listView,
                               int group) {
    ExpandableListAdapter listAdapter = (ExpandableListAdapter) listView.getExpandableListAdapter();
    int totalHeight = 0;
    int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
            View.MeasureSpec.EXACTLY);
    for (int i = 0; i < listAdapter.getGroupCount(); i++) {
        View groupItem = listAdapter.getGroupView(i, false, null, listView);
        groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);

        totalHeight += groupItem.getMeasuredHeight();

        if (((listView.isGroupExpanded(i)) && (i != group))
                || ((!listView.isGroupExpanded(i)) && (i == group))) {
            for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {
                View listItem = listAdapter.getChildView(i, j, false, null,
                        listView);
                listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);

                totalHeight += listItem.getMeasuredHeight();

            }
        }
    }

    ViewGroup.LayoutParams params = listView.getLayoutParams();
    int height = totalHeight
            + (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
    if (height < 10)
        height = 200;
    params.height = height;
    listView.setLayoutParams(params);
    listView.requestLayout();

}

An call this method in your setOnGroupClickListener.like below

mExpandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {

            setListViewHeight(parent, groupPosition);
            return false;
        }
    });
3

The answer from V-rund Puro-hit is what worked for me. But it took some modifications to work with Kotlin supporting API >19. So for the purpose of saving someone time, here it is:

Create a new class file NonScrollExpandableListView:

import android.content.Context
import android.util.AttributeSet
import android.widget.ExpandableListAdapter
import android.widget.ExpandableListView


class NonScrollExpandableListView : ExpandableListView {

    constructor(context: Context) : super(context) {}

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}

    override fun setAdapter(adapter: ExpandableListAdapter?) {
        super.setAdapter(adapter)
    }

    override fun setOnChildClickListener(onChildClickListener: OnChildClickListener) {
        super.setOnChildClickListener(onChildClickListener)
    }

    override fun expandGroup(groupPos: Int) : Boolean {
        return super.expandGroup(groupPos)
    }

    override fun expandGroup(groupPos: Int, animate: Boolean) : Boolean {
        return super.expandGroup(groupPos, animate)
    }

    override fun isGroupExpanded(groupPosition: Int): Boolean {
        return super.isGroupExpanded(groupPosition)
    }

    public override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE shr 2, MeasureSpec.AT_MOST)
        super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom)
        val params = layoutParams
        params.height = measuredHeight
    }
}

...and I use it like so:

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >

            <com.example.you.kotlinlistview.NonScrollExpandableListView
                android:id="@+id/expandableCategories"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                />

            <Button
                android:id="@+id/add_new_feed"
                android:drawableStart="@drawable/ic_add"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Add new feed"
                />

            <Button
                android:id="@+id/settings_button"
                android:drawableStart="@drawable/ic_settings"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Settings"
                />

            <Button
                android:id="@+id/logout_button"
                android:drawableStart="@drawable/ic_exit"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="Log Out"
                />

        </LinearLayout>
    </ScrollView>

As a result, I can comfortably add buttons and other elements to NavigationView side drawer) and it all works nicely in one common ScrollView. Main usage here is when you need to combine multiple ListViews and ExpandableListViews inside the one common ScrollView which would take care of scrolling.

dsalaj
  • 1,947
  • 3
  • 22
  • 36
  • How to do the same for ListView instead of ExpandableListView??Please help? – KJEjava48 Jul 11 '19 at 07:42
  • @KJEjava48 In the exact same way, you just need to override `ListView` class, and you don't need to override all the `expand...` classes. You can post a new question if you think it's beneficial to have the code for exactly that case (if you do, don't forget to refer to this question). – dsalaj Jul 11 '19 at 13:20
  • ok thank you.Can u explain what does this means in ur code Integer.MAX_VALUE shr 2 ?? what here 2 stands for?? – KJEjava48 Jul 11 '19 at 13:28
  • for me it worked only after i changed Integer.MAX_VALUE >> 2 to Integer.MAX_VALUE >> 21 . Why its so? Also it work's with ScrollView not with NestedScrollView. – KJEjava48 Jul 12 '19 at 06:08
  • @KJEjava48 In Kotlin `shr` is the keyword for [shift right operation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/shr.html). Regarding the MeasureSpec it is good to start with [docs](https://developer.android.com/reference/android/view/View.MeasureSpec.html#makeMeasureSpec(int,%20int)). But generally this allows the expandable list view to change height depending on its state (expanded groups), instead of having a fixed height and becoming scrollable. – dsalaj Jul 12 '19 at 13:29
  • when i make it to 21 or 22 list is scrolling otherwise not scrolling... – KJEjava48 Jul 12 '19 at 16:49
  • It should not be scrolling. That was the whole point. You want to make it non-scrolling so you can combine it with other views. Then you make the whole thing scrollable by putting all these views inside a one common ScrollView. – dsalaj Jul 12 '19 at 18:43
  • Seems like this will not work correctly for 3 level or 4 level ExpandableListview. Any help ?? – KJEjava48 Jul 26 '19 at 14:02
  • Scrolling is not smooth. – Hiren Patel Jan 31 '20 at 06:08
  • @HirenPatel I think the smoothness of scrolling is something one solves with profiling. If the drawing of the list elements takes a significant amount of computation it causes skipped frames. This is an independent issue, different from grouping the elements in a single srollable view. Or is this solution causing a significant computation overhead for you? – dsalaj Feb 01 '20 at 18:51
  • super.onMeasure is throwing exception – Dan Ponce Dec 21 '20 at 14:44
0

We can't use listview, gridview or expandable listview inside scrollview. If you wan't to use expandable listview inside scrollview then you have to give some fixed height to your expandable listview.

Kumar M
  • 914
  • 6
  • 19
  • Oh I see, so it has to be a fixed height.. If I give a fixed height, for example 40 dp, would it take that much space even if it is expanded? And how do people make `ExpandableListView` inside another scrolling view? I've seen several apps like that.. – Kevin Murvie Jun 03 '16 at 04:09
  • @KevinMurvie By default android won't fully support one scrollable view inside another scrollable view. But we can do something and it can be done. But it will not be a perfect one. [For your reference](http://stackoverflow.com/questions/6210895/listview-inside-scrollview-is-not-scrolling-on-android/11554684#11554684) – Kumar M Jun 03 '16 at 04:25
  • Actually I've seen that and I've applied that (RecyclerView inside NestedScrollView).. But too bad it has performance issues and I do it with recyclerview.. So those apps actually doesn't play by the rules? – Kevin Murvie Jun 03 '16 at 04:29
  • Exactly, we can do something and we can achieve that type of scrolling but it will have performance and scrolling issues. – Kumar M Jun 03 '16 at 04:32
  • I see then.. Thanks for the information, I shall find the best method to cause lesser performance issue.. Hopefully it can be done soon :D – Kevin Murvie Jun 03 '16 at 11:14