Search code examples
androidlistviewlistviewitem

Load data into an ExpandableListView


I am searching for a way to load data into an Expandale List View, the output I want to resemble the one of the picture attached here In order this to be done dynamically, is it better to be read from a csv? Or to create a DB? Furthermore, on a sub-item press, I want a ScrollView to appear.

Here is the code so far: The layout of the activity:

<?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="wrap_content">

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

        <TextView
            android:id="@+id/android:empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
</LinearLayout>

The itemlayout:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView android:id="@+id/grp_child"
        android:paddingLeft="50dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

And the subitem:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView android:id="@+id/row_name"
        android:paddingLeft="50dp"
        android:focusable="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

In the activity, I have hardcoded some values so far, using some tutorials I came across:

 public void onCreate(Bundle savedInstanceState) {
        try{
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_photographers);

            SimpleExpandableListAdapter expListAdapter =
                    new SimpleExpandableListAdapter(
                            this,
                            createGroupList(),             
                            R.layout.group_row,             
                            new String[] { "Group Item" },  
                            new int[] { R.id.row_name },    
                            createChildList(),              
                            R.layout.child_row,             
                            new String[] {"Sub Item"},      
                            new int[] { R.id.grp_child}     
                    );
            setListAdapter( expListAdapter );
        }catch(Exception e){
            System.out.println("Errrr +++ " + e.getMessage());
        }
    }

    /* Creating the Hashmap for the row */

    @SuppressWarnings("unchecked")
    private List createGroupList() {
        ArrayList result = new ArrayList();
        for( int i = 0 ; i < 15 ; ++i ) { // 15 groups........
            HashMap m = new HashMap();
            m.put( "Group Item","Group Item " + i ); // the key and it's value.
            result.add( m );
        }
        return (List)result;
    }

    @SuppressWarnings("unchecked")
    private List createChildList() {
        ArrayList result = new ArrayList();
        for( int i = 0 ; i < 15 ; ++i ) { // this -15 is the number of groups(Here it's fifteen)
          /* each group need each HashMap-Here for each group we have 3 subgroups */
            ArrayList secList = new ArrayList();
            for( int n = 0 ; n < 3 ; n++ ) {
                HashMap child = new HashMap();
                child.put( "Sub Item", "Sub Item " + n );
                secList.add( child );
            }
            result.add( secList );
        }
        return result;
    }


    public void  onContentChanged  () {
        System.out.println("onContentChanged");
        super.onContentChanged();
    }

    /* This function is called on each child click */
    public boolean onChildClick( ExpandableListView parent, View v, int groupPosition,int childPosition,long id) {
        System.out.println("Inside onChildClick at groupPosition = " + groupPosition +" Child clicked at position " + childPosition);
        return true;
    }


    /* This function is called on expansion of the group */
    public void  onGroupExpand  (int groupPosition) {
        try{
            System.out.println("Group expanding Listener => groupPosition = " + groupPosition);
        }catch(Exception e){
            System.out.println(" groupPosition Errrr +++ " + e.getMessage());
        }
    }

I am wondering if it is a good idea to store the data I want to show in separate csv files (one storing the data for the items, one for the subitems. one for the extra information in the ScrollView), to have id-s for identification and to directly read from the CSVs with the OpenCSVReader?

I would appreciate any pieces of advice, Thanks


Solution

  • create adapter for your expandable listView. like that

    public class ExpandableAdapter extends BaseExpandableListAdapter {
        private final Context context;
        private final List<Menu> parentObjects;
    
        public ExpandableAdapter(Context context, ArrayList<Menu> parentObjects) {
            this.context = context;
            this.parentObjects = parentObjects;
    
        }
    
        @Override
        public int getGroupCount() {
            return parentObjects.size();
        }
    
        @Override
        public int getChildrenCount(int i) {
            return parentObjects.get(i).childMenu.size();
        }
    
        @Override
        public Menu getGroup(int i) {
            return parentObjects.get(i);
        }
    
        @Override
        public Menu.ChildMenu getChild(int i, int i2) {
            return parentObjects.get(i).childMenu.get(i2);
        }
    
        @Override
        public long getGroupId(int i) {
            return i;
        }
    
        @Override
        public long getChildId(int i, int i2) {
            return 0;
        }
    
        @Override
        public boolean hasStableIds() {
            return false;
        }
    
        @Override
        public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
            Menu currentParent = parentObjects.get(i);
            if (view == null) {
                LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context
                        .LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.navdrawer_parent_item, viewGroup,false);
            }
    
            ImageView imageViewIndicator = (ImageView) view.findViewById(R.id.imageViewNav);
            if (getChildrenCount(i) == 0)
                imageViewIndicator.setVisibility(View.GONE);
            else
                imageViewIndicator.setVisibility(View.VISIBLE);
    
            TextView textViewNavMenuName = (TextView) view.findViewById(R.id.textViewNavParentMenuName);
            ImageView imageViewIcon = (ImageView) view.findViewById(R.id.imageViewIcon);
            String base64 = currentParent.getImage();
            if (base64 != null && !base64.equals("")) {
                byte[] imageAsBytes = Base64.decode(currentParent.getImage().getBytes(), Base64
                        .DEFAULT);
                imageViewIcon.setImageBitmap(BitmapFactory.decodeByteArray(imageAsBytes, 0,
                        imageAsBytes.length));
    
            } else
                imageViewIcon.setImageResource(R.drawable.ic_action_android);
    
            textViewNavMenuName.setText(currentParent.getMenuName());
            return view;
        }
    
    
    
        @Override
        public View getChildView(int groupPosition, int childPosition, boolean b, View view,
                                 ViewGroup viewGroup) {
            Menu currentChild = getGroup(groupPosition);
            if (view == null) {
                LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context
                        .LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.navdrawer_child_item, viewGroup,false);
            }
            View divider = view.findViewById(R.id.divider);
            if (b)
                divider.setVisibility(View.VISIBLE);
            else
                divider.setVisibility(View.GONE);
    
            TextView textViewNavMenuName = (TextView) view.findViewById(R.id.textViewNavChildMenuName);
            textViewNavMenuName.setText(currentChild.childMenu.get(childPosition).getMenuName());
    
            return view;
        }
    
        @Override
        public boolean isChildSelectable(int i, int i2) {
            return true;
        }
    }
    

    and the model for the expandable listView like

    public class Menu {
        private int AssociatedApp;
        private String MenuName;
        private String NavigateURL;
        private String ActivityName;
        private String Image;
        private int MenuID;
        public ArrayList<ChildMenu> childMenu;
    
        public ArrayList<ChildMenu> getChildMenu() {
            return childMenu;
        }
    
        public void setChildMenu(ArrayList<ChildMenu> childMenu) {
            this.childMenu = childMenu;
        }
    
        public int getAssociatedApp() {
            return AssociatedApp;
        }
    
        public void setAssociatedApp(int associatedApp) {
            AssociatedApp = associatedApp;
        }
    
        public String getMenuName() {
            return MenuName;
        }
    
        public void setMenuName(String menuName) {
            MenuName = menuName;
        }
    
        public String getNavigateURL() {
            return NavigateURL;
        }
    
        public void setNavigateURL(String navigateURL) {
            NavigateURL = navigateURL;
        }
    
        public String getActivityName() {
            return ActivityName;
        }
    
        public void setActivityName(String activityName) {
            ActivityName = activityName;
        }
    
        public String getImage() {
            return Image;
        }
    
        public void setImage(String image) {
            Image = image;
        }
    
    
        public Menu() {
        }
    
        public int getMenuID() {
            return MenuID;
        }
    
        public class ChildMenu {
            private int AssociatedApp;
            private String MenuName;
            private String NavigateURL;
            private String ActivityName;
            private String Image;
            private int MenuID;
            public ChildMenu(String menuName, String activityName) {
                this.MenuName = menuName;
                this.ActivityName=activityName;
            }
            public ChildMenu() {
    
            }
            public int getAssociatedApp() {
                return AssociatedApp;
            }
    
            public void setAssociatedApp(int associatedApp) {
                AssociatedApp = associatedApp;
            }
    
            public String getMenuName() {
                return MenuName;
            }
    
            public void setMenuName(String menuName) {
                MenuName = menuName;
            }
    
            public String getNavigateURL() {
                return NavigateURL;
            }
    
            public void setNavigateURL(String navigateURL) {
                NavigateURL = navigateURL;
            }
    
            public String getActivityName() {
                return ActivityName;
            }
    
            public void setActivityName(String activityName) {
                ActivityName = activityName;
            }
    
            public String getImage() {
                return Image;
            }
    
            public void setImage(String image) {
                Image = image;
            }
    
            public int getMenuID() {
                return MenuID;
            }
        }
    
    }
    

    ok now you can create your menu with data and bindwith expandable listview

     elv = (ExpandableListView)findViewById(R.id.elv);
            elv.setOnGroupExpandListener(onGroupExpandListenser);
            MyExpandableAdapter adapter = new MyExpandableAdapter(this, getData());//where getData() will return list of data.
            elv.setAdapter(adapter);
    

    parent xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="fill_parent"
                  android:layout_height="wrap_content"
                  android:orientation="vertical">
    
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:paddingBottom="12dp"
            android:paddingLeft="12dp"
            android:paddingTop="12dp">
    
            <ImageView
                android:contentDescription="@string/app_name"
    
                android:id="@+id/imageViewIcon"
                android:layout_width="35dp"
                android:layout_height="35dp"
                android:layout_alignParentLeft="true"
                android:layout_margin="4dp"
               />
    
            <TextView
                android:id="@+id/textViewNavParentMenuName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@+id/imageViewNav"
                android:layout_toRightOf="@+id/imageViewIcon"
                android:padding="10dp"
                android:textSize="15sp"/>
    
            <ImageView
                android:contentDescription="@string/app_name"
                android:id="@+id/imageViewNav"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_margin="4dp"
                android:src="@drawable/ic_action_more_nav"
                />
        </RelativeLayout>
    
        <include
            layout="@layout/divider"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
    </LinearLayout>
    

    child xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:gravity="center_vertical"
    
                  android:orientation="vertical">
    
        <TextView
            android:id="@+id/textViewNavChildMenuName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="45dp"
            android:gravity="center_vertical"
            android:text="TextView"
            android:padding="16dp"/>
    
        <include
            layout="@layout/divider"
            android:layout_width="match_parent"
            android:layout_height="fill_parent"/>
    </LinearLayout>
    

    adding listener for expandable listView like this. groupExpandlistener is used for collasping other groups while open one

    private int lastExpandedPosition = -1;
    

    for setting up listener

     elv.setOnChildClickListener(new DrawerItemClickListener());
            elv.setOnGroupClickListener(new DrawerItemClickListener());
            elv.setOnGroupExpandListener(new DrawerItemClickListener());
    
        private class DrawerItemClickListener implements ExpandableListView.OnChildClickListener,
            ExpandableListView.OnGroupClickListener, ExpandableListView.OnGroupExpandListener {
        @Override
        public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int
                childPosition, long id) {
            selectItem(childPosition, navigationConfig.getBaseExpandableListAdapter
                    ().getChild
                    (groupPosition, childPosition));
            return true;
        }
    
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
    
            selectItem(groupPosition, navigationConfig.getBaseExpandableListAdapter
                    ().getGroup
                    (groupPosition));
            return false;
        }
    
        @Override
        public void onGroupExpand(int groupPosition) {
            if (lastExpandedPosition != -1
                    && groupPosition != lastExpandedPosition) {
                expandableListView.collapseGroup(lastExpandedPosition);
            }
            lastExpandedPosition = groupPosition;
        }
    }
    

    for sample data use to bind with getData(). note create constructor in model class as given in getData()

    //Sample data for expandable list view.
        public List<Menu> getData()
        {
            List<Menu> parentObjects = new ArrayList<Menu>();
            for (int i = 0; i<20; i++)
            {
                parentObjects.add(new Menu("Mother " +i, "Father " +i, "Header " + i, "Footer " +i, getChildren(i)));
    
            }
            return parentObjects;
        }
    
        private List<Menu.ChildMenu> getChildren(int childCount)
        {
            List<Menu.ChildMenu> childObjects = new ArrayList<Menu.ChildMenu>();
            for (int i =0; i<childCount; i++)
            {
                childObjects.add(new Menu.ChildMenu("Child " + (i+1), 10 +i ));
            }
            return childObjects;
        }