How can I put a ExpandableListView into a ScrollView without it collapsing?
Asked Answered
F

4

3

I want to use ExpandableListView inside ScrollView with other views but i faced the problem of self scroller in ExpandableListView l tried to disable it but the problem is with the height of the ExpandableListView and the layout it's inside. So i want to

  • Disable ExpandableListView scroll
  • Resize ExpandableListView & LinearLayout that contains when groupView is clicked

I googled a solution and i found one for that works for ListView only

Listview in ScrollView

I want to make the same workout but with ExpandableListView (with custom Adapter).

Here is My Code: MainActivity.java

package fablabegypt.android.expandablelistview2;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.LinearLayout;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


public class MainActivity extends ActionBarActivity {

    mListAdapter listAdapter;
    ExpandableListView expListView;
    LinearLayout linearLayout;
    List<String> listDataHeader;
    HashMap<String, List<String>> listDataChild;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        linearLayout = (LinearLayout) findViewById(R.id.linear_holder);

        prepareListData();
        expListView = (ExpandableListView) findViewById(R.id.expand_list);
    //expListView.setScrollContainer(false);
    expListView.setHorizontalScrollBarEnabled(false);
    expListView.setVerticalScrollBarEnabled(false);
    expListView.setFastScrollEnabled(false);
    expListView.setSmoothScrollbarEnabled(false);
    //expListView.setOverscrollHeader(null);
    expListView.setFooterDividersEnabled(false);
    //expListView.setOverscrollFooter(null);
    //expListView.setVerticalFadingEdgeEnabled(false);
    //expListView.setHorizontalFadingEdgeEnabled(false);
    expListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
        @Override
        public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
            return true;
        }
    });
    expListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
            if (parent.isGroupExpanded(groupPosition)) {
                parent.collapseGroup(groupPosition);
            } else {
                parent.expandGroup(groupPosition);
            }
            //telling the listView we have handled the group click, and don't want the default actions.
            return true;
        }
    });
    expListView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                return false;
            }else {

            }
            return true;
        }
    });
    listAdapter = new mListAdapter(this, listDataHeader,listDataChild);
    expListView.setAdapter(listAdapter);
}
private void prepareListData() {
    listDataHeader = new ArrayList<String>();
    listDataChild = new HashMap<String, List<String>>();

    // Adding child data
    listDataHeader.add("Top 250");
    listDataHeader.add("Now Showing");
    listDataHeader.add("Coming Soon..");

    // Adding child data
    List<String> top250 = new ArrayList<String>();
    top250.add("The Shawshank Redemption");
    top250.add("The Godfather");
    top250.add("The Godfather: Part II");
    top250.add("Pulp Fiction");
    top250.add("The Good, the Bad and the Ugly");
    top250.add("The Dark Knight");
    top250.add("12 Angry Men");

    List<String> nowShowing = new ArrayList<String>();
    nowShowing.add("The Conjuring");
    nowShowing.add("Despicable Me 2");
    nowShowing.add("Turbo");
    nowShowing.add("Grown Ups 2");
    nowShowing.add("Red 2");
    nowShowing.add("The Wolverine");

    List<String> comingSoon = new ArrayList<String>();
    comingSoon.add("2 Guns");
    comingSoon.add("The Smurfs 2");
    comingSoon.add("The Spectacular Now");
    comingSoon.add("The Canyons");
    comingSoon.add("Europa Report");

    listDataChild.put(listDataHeader.get(0), top250); // Header, Child data
    listDataChild.put(listDataHeader.get(1), nowShowing);
    listDataChild.put(listDataHeader.get(2), comingSoon);
}



@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        finish();
        return true;
    }

        return super.onOptionsItemSelected(item);
    }
}

mListAdapter.java

package fablabegypt.android.expandablelistview2;

import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.TextView;

import java.util.HashMap;
import java.util.List;

/**
 * Created by Mouso on 4/27/2015.
 */
public class mListAdapter extends BaseExpandableListAdapter {

    private Context context;
    private List<String> header_list;
    private HashMap<String, List<String>> children_data_list;

    public mListAdapter(Context context,List<String> header_list,HashMap<String,List<String>> children_data_list){
        this.context = context;
        this.header_list = header_list;
        this.children_data_list = children_data_list;
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }

    @Override
    public int getGroupCount() {
        return this.children_data_list.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return this.children_data_list.get(this.header_list.get(groupPosition)).size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return this.header_list.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return this.children_data_list.get(this.header_list.get(groupPosition)).get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        final String headerText = (String) getGroup(groupPosition);
        if (convertView == null){
            LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_group,null);
        }

        TextView headerTxt = (TextView) convertView.findViewById(R.id.list_group_txt);
        headerTxt.setTextSize(20);
        headerTxt.setText(headerText);
        //Log.d("Mouso",headerText);

        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        final String childText = (String) getChild(groupPosition,childPosition);

        if (convertView == null){
            LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_item,null);
        }

        TextView childTxt = (TextView) convertView.findViewById(R.id.list_child_txt);
        childTxt.setText(childText);

        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return true;
    }

    @Override
    public boolean isEmpty() {
        if (header_list.size() > 0)
            return true;
        return false;
    }

    @Override
    public void onGroupExpanded(int groupPosition) {

    }

    @Override
    public void onGroupCollapsed(int groupPosition) {

    }

    @Override
    public long getCombinedChildId(long groupId, long childId) {
        return (groupId*100)+childId;
    }

    @Override
    public long getCombinedGroupId(long groupId) {
        return groupId;
    }

}

activity_main.xml

<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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <ScrollView
        android:layout_width="wrap_content"
        android:layout_height="500px"
        android:fillViewport="true">
    <LinearLayout
        android:id="@+id/linear_holder"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/txt"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="we 7yat 3neak we fadaha 3neya \n\n\n dana ba7ebak ad 3naya"/>

        <ExpandableListView
            android:id="@+id/expand_list"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:isScrollContainer="false">

        </ExpandableListView>
    </LinearLayout>
    </ScrollView>

</RelativeLayout>

list_group.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/list_group_txt"
        android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />


</LinearLayout>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/list_child_txt"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

My Try for implmenting the workout

Helper.java

package fablabegypt.android.expandablelistview2;

import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ListAdapter;
import android.widget.ListView;

/**
 * Created by Mouso on 4/29/2015.
 */
public class ListViewHelper {
    public static void getListViewSize(ExpandableListView myListView) {
        ListAdapter myListAdapter = myListView.getAdapter();

        if (myListAdapter == null) {
            //do nothing return null
            return;
        }
        //set listAdapter in loop for getting final size
        int totalHeight = 0;
        for (int groupSize = 0; groupSize < myListAdapter.getGroupCount(); groupSize++) {
            View listItem = myListAdapter.getGroupView(groupSize, false, null, myListView);
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
            for (int size = 0; size < myListAdapter.getChildrenCount(groupSize); size++) {
                if (size == myListAdapter.getChildrenCount(groupSize)-1)
                    listItem = myListAdapter.getChildView(groupSize, size, true, null, myListView);
                listItem = myListAdapter.getChildView(groupSize, size, false, null, myListView);
                listItem.measure(0, 0);
                totalHeight += listItem.getMeasuredHeight();
            }
        }
        //setting listview item in adapter
        ViewGroup.LayoutParams params = myListView.getLayoutParams();
        params.height = totalHeight + (myListView.getDividerHeight() * (myListAdapter.getGroupCount() - 1));
        myListView.setLayoutParams(params);
        // print height of adapter on log
        Log.d("mouso", "height of listItem:"+String.valueOf(totalHeight));
    }

    //Read more: http://www.androidhub4you.com/2012/12/listview-into-scrollview-in-android.html#ixzz3Yh4m4MPG

}
Favouritism answered 29/4, 2015 at 12:20 Comment(2)
MANTRA: Never put a scrollable View inside a ScrollView. Repeat at least a million times.Ohalloran
Refer to my answer on this SO post, might give u some idea or hint. https://mcmap.net/q/894122/-expandable-listview-inside-scrollviewPraetorian
N
3

Extend the ExpandableListView class and set expand to false

    public class CustomExpandableListView extends ExpandableListView {

    boolean expanded = false;

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

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

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

    public boolean isExpanded() {
        return expanded;
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        if (isExpanded()) {
            int expandSpec = MeasureSpec.makeMeasureSpec(
                    Integer.MAX_VALUE >> 2, 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;
    }
}

In your activity class

CustomExpandableListView customExpandableListView = (CustomExpandableListView ) findViewById(R.id.expandable_list);
customExpandableListView .setExpanded(true);

Layout file

 <com.xxx.xxx.util.ExpandableHeightListView
                    android:id="@+id/expandable_list"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    />

Now It will work within a scroll view

Ney answered 4/8, 2017 at 7:16 Comment(0)
Y
3

I have same problemm

I solve this problem adding header and footer in ExpandableListView

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

             <ExpandableListView
                android:id="@+id/listview"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

            </ExpandableListView>

        </LinearLayout>
    </ScrollView>

/// add header

ExpandableListView listview

ViewGroup headerView = (ViewGroup) getLayoutInflater().inflate(R.layout.item_header, listview, false);

listview.addHeaderView(headerView_right);

*/// add footer*


ViewGroup footerview= (ViewGroup) getLayoutInflater().inflate(R.layout.item_footer, listview, false);

listview.addFooterView(headerView_right);
Yablon answered 10/10, 2017 at 7:24 Comment(0)
W
2

It is ALWAYS a very bad idea to put a view that has it's own scrolling functionality inside another view with scrolling functionality. This can lead to touch actions being intercepted by the wrong view, poor performance, etc. Also, from your main layout, you don't seem to be using the ScrollView for anything other than making the TextView scroll with the list view. Why not add it as a header view? expListView.setHeaderView(View) and inflate the textview into it.

Worl answered 29/4, 2015 at 12:46 Comment(0)
N
1

As I can see in your "activity_main.layout" I think you want to put the ExpandableListView to make the textview scroll always with the List, isn't it?

You have two solutions.

-The prettiest and easiest solution is to put the textview as a header of the ExpandableListView using

list.addHeaderView(listHeader,null,false); 

important: Using "false" as the third the header can't be clicked as a row.

-The other solution is to call "getListViewSize()" every time you call "parent.collapseGroup(groupPosition)" or "parent.expandGroup(groupPosition);" I know using a listview inside a scrollview is not recommended but sometimes is useful. Unfortunately this isn't that case, I recommend to use the first solution.

I hope I could help you.

Newmann answered 29/4, 2015 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.