androidexpandablelistviewcheckedtextview

Uncheck all CheckedTextViews in ExpandableListView Group


I'm right now trying to set up an ExpandableListView inside my fragment with following behaviour. I have three Groups with CheckedTextViews:

  1. Brands (VW,AUDI, SEAT ...)
  2. Types (Polo,Golf, A3, A2, Ibiza ...)
  3. Colors (Red, Green, Blue ...)

On expanding one group the other groups should close (already managed). On click on one child of one group it is shown as selected (already managed).

This is were I'm stuck right now

On click on another child of the same group the other item should be deselected. Also automatically the next group should open after for example

  1. If child 1 in group 1 is selected and child 2 in group 1 is clicked
  2. Child 1 should be deselected and
  3. Group 2 should expand
  4. Now you have to select child in group 2 (which also deselects the other selected child in this group)
  5. Group 3 opens
  6. Select child of group 3 --> all groups collapse

In future the Arraylists will be retrieved dynamically from the server. After this there should be a behaviour to show only cartypes of the selected brand in the first group. Perhaps you also have an idea how to solve this.

My code is

package de.tubs.cs.ibr.androidlab.flexcarpool.ui;

import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import de.tubs.cs.ibr.androidlab.flexcarpool.R;

public class ConfigureCarFragment extends Fragment implements View.OnClickListener {

    ExpandableListView expandableListView;
    ExpandableListAdapter expandableListAdapter;
    List<String> expandableListTitle;
    HashMap<String, List<String>> expandableListDetail;
    private int lastExpandedPosition = -1;



    private String[] mBrand;
    private String[] mTypes;
    private String[] mColors;

    private Button configure_car;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_car_configure, container, false);
        setHasOptionsMenu(true);
        mColors = getResources().getStringArray(R.array.colors);
        mBrand = getResources().getStringArray(R.array.brands);
        mTypes = getResources().getStringArray(R.array.types);

        expandableListView = (ExpandableListView) view.findViewById(R.id.expandableListView);

        ((MainActivity) getActivity())
                .setActionBarTitle(getString(R.string.profil));

        expandableListDetail = ConfigureCarData.getData();
        expandableListTitle = new ArrayList<String>(expandableListDetail.keySet());
        expandableListAdapter = new ConfigureCarAdapter( (MainActivity)getContext(), expandableListTitle, expandableListDetail);
        expandableListView.setAdapter(expandableListAdapter);


        expandableListView.setAdapter(expandableListAdapter);
        expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {

            @Override

            public void onGroupExpand(int groupPosition) {

                    if (lastExpandedPosition != -1
                            && groupPosition != lastExpandedPosition) {
                        expandableListView.collapseGroup(lastExpandedPosition);
                    }
                    lastExpandedPosition = groupPosition;
                            }
        });

        expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {

            @Override
            public void onGroupCollapse(int groupPosition) {

            }
        });

        expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                                        int groupPosition, int childPosition, long id) {


                long childcount = expandableListAdapter.getChildrenCount(groupPosition);

                CheckedTextView checkbox = (CheckedTextView) v.findViewById(R.id.expandedListItem);

                if (checkbox.isChecked()) {

                    checkbox.setCheckMarkDrawable(null);
                    checkbox.setChecked(false);
                } else {

                    checkbox.setCheckMarkDrawable(R.drawable.ic_check_black_24dp);
                    checkbox.setChecked(true);
                }

                return true;
            }
        });

        configure_car = view.findViewById(R.id.configure_car);


        configure_car.setOnClickListener(this);

        ((MainActivity) getActivity())
                .setActionBarTitle(getString(R.string.configure_car));


        return view;
    }

    public void onPrepareOptionsMenu(Menu menu) {
        menu.clear();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.configure_car:
                ((MainActivity) getActivity()).getSupportFragmentManager().popBackStack();

        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        getActivity().setTitle(R.string.login);
    }

 }

The code of the Adapter is

package de.tubs.cs.ibr.androidlab.flexcarpool.ui;

import java.util.HashMap;
import java.util.List;
import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

import de.tubs.cs.ibr.androidlab.flexcarpool.R;


public class ConfigureCarAdapter extends BaseExpandableListAdapter{


        private Context context;
        private List<String> expandableListTitle;
        private HashMap<String, List<String>> expandableListDetail;

        public  ConfigureCarAdapter(Context context, List<String> expandableListTitle,
                                           HashMap<String, List<String>> expandableListDetail) {
            this.context = context;
            this.expandableListTitle = expandableListTitle;
            this.expandableListDetail = expandableListDetail;

        }

        @Override
        public Object getChild(int listPosition, int expandedListPosition) {
            return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
                    .get(expandedListPosition);
        }

        @Override
        public long getChildId(int listPosition, int expandedListPosition) {
            return expandedListPosition;
        }

        @Override
        public View getChildView(int listPosition, final int expandedListPosition,
                                 boolean isLastChild, View convertView, ViewGroup parent) {
            final String expandedListText = (String) getChild(listPosition, expandedListPosition);
            if (convertView == null) {
                LayoutInflater layoutInflater = (LayoutInflater) this.context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = layoutInflater.inflate(R.layout.list_item, null);
            }
            TextView expandedListTextView = (TextView) convertView
                    .findViewById(R.id.expandedListItem);
            expandedListTextView.setText(expandedListText);
            return convertView;
        }

        @Override
        public int getChildrenCount(int listPosition) {
            return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
                    .size();
        }

        @Override
        public Object getGroup(int listPosition) {
            return this.expandableListTitle.get(listPosition);
        }

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

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

        @Override
        public View getGroupView(int listPosition, boolean isExpanded,
                                 View convertView, ViewGroup parent) {
            String listTitle = (String) getGroup(listPosition);
            if (convertView == null) {
                LayoutInflater layoutInflater = (LayoutInflater) this.context.
                        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = layoutInflater.inflate(R.layout.list_group, null);
            }
            TextView listTitleTextView = (TextView) convertView
                    .findViewById(R.id.listTitle);
            listTitleTextView.setTypeface(null, Typeface.BOLD);
            listTitleTextView.setText(listTitle);
            return convertView;
        }

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

        @Override
        public boolean isChildSelectable(int listPosition, int expandedListPosition) {
            return true;
        }
}

Thanks for your help, I'm quit a newbie so please be patient!


Solution

  • Try below code:

    fragment_car_configure.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">
    
    <Button
        android:id="@+id/configure_car"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />
    
    <Button
        android:id="@+id/btConfirmCar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:text="Confirm Car"/>
    
    <ExpandableListView
        android:id="@+id/expandableListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ExpandableListView>
    
    </LinearLayout>
    

    list_group1.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:padding="8dp"
    android:background="@color/colorPrimary"
    android:layout_height="wrap_content">
    
    <TextView
        android:id="@+id/listTitle"
        android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
        android:textSize="16dp"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
    <TextView
        android:id="@+id/selectedChild"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#ff0000"
        android:gravity="right"
        android:text="Test"/>
    
    </LinearLayout>
    

    list_item1.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="55dip">
    
    <CheckedTextView
        android:id="@+id/expandedListItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checkMark="?android:attr/listChoiceIndicatorMultiple"
        android:paddingBottom="5dp"
        android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
        android:paddingTop="5dp"
        android:text="Child"
        android:textSize="16dip" />
    
    </LinearLayout>
    

    ConfigureCarFragment.java:

    public class ConfigureCarFragment extends Fragment implements View.OnClickListener {
    ExpandableListView expandableListView;
    ConfigureCarAdapter expandableListAdapter;
    List<String> expandableListTitle;
    LinkedHashMap<String, List<String>> expandableListDetail;
    private int lastExpandedPosition = -1;
    
    private String[] mBrand;
    private String[] mTypes;
    private String[] mColors;
    
    private Button configure_car;
    private Button btConfirmCar;
    
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_car_configure, container, false);
        setHasOptionsMenu(true);
        mBrand = getResources().getStringArray(R.array.brands);
        mTypes = getResources().getStringArray(R.array.types);
        mColors = getResources().getStringArray(R.array.colors);
    
        expandableListView = view.findViewById(R.id.expandableListView);
    
        //((MainActivity) getActivity()).setActionBarTitle(getString(R.string.profil));
    
        //expandableListDetail = ConfigureCarData.getData();
        expandableListDetail = getData();
        expandableListTitle = new ArrayList<>(expandableListDetail.keySet());
        expandableListAdapter = new ConfigureCarAdapter( (MainActivity)getContext(), expandableListTitle, expandableListDetail);
        expandableListView.setAdapter(expandableListAdapter);
    
        expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                if (lastExpandedPosition != -1 && groupPosition != lastExpandedPosition) {
                    expandableListView.collapseGroup(lastExpandedPosition);
                }
                lastExpandedPosition = groupPosition;
            }
        });
        expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
            @Override
            public void onGroupCollapse(int groupPosition) {}
        });
        expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                expandableListAdapter.updateWithChildSelected(groupPosition, childPosition);
                if(groupPosition < expandableListAdapter.getGroupCount() - 1){
                    expandableListView.expandGroup(groupPosition + 1);
                    btConfirmCar.setVisibility(View.GONE);
                }else{
                    expandableListView.collapseGroup(expandableListAdapter.getGroupCount() - 1);
                    btConfirmCar.setVisibility(View.VISIBLE);
                }
                return true;
            }
        });
    
        configure_car = view.findViewById(R.id.configure_car);
        configure_car.setOnClickListener(this);
        //((MainActivity) getActivity()).setActionBarTitle(getString(R.string.configure_car));
    
        btConfirmCar = view.findViewById(R.id.btConfirmCar);
        btConfirmCar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showConfirmedCar("Your confirmed car configuration is:\n");
            }
        });
    
        expandableListView.expandGroup(0);
        return view;
    }
    
    private void showConfirmedCar(String header){
        String msg = header;
        for(int i=0; i<expandableListAdapter.getGroupCount(); i++) {
            msg += expandableListAdapter.getGroup(i) + ": " +
                    expandableListAdapter.getChild(i, expandableListAdapter.checkedChildPosition[i]) + "\n";
        }
        Toast.makeText(getContext(), msg, Toast.LENGTH_LONG).show();
    }
    
    public void onPrepareOptionsMenu(Menu menu) {
        menu.clear();
    }
    
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.configure_car:
                ((MainActivity) getActivity()).getSupportFragmentManager().popBackStack();
        }
    }
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        //getActivity().setTitle(R.string.login);
    }
    
    private LinkedHashMap<String, List<String>> getData(){
        LinkedHashMap<String, List<String>> listHashMap = new LinkedHashMap<>();
        List<String> list;
        list = new ArrayList<>();
        list.addAll(Arrays.asList(mBrand));
        listHashMap.put("Brand", list);
        list = new ArrayList<>();
        list.addAll(Arrays.asList(mTypes));
        listHashMap.put("Type", list);
        list = new ArrayList<>();
        list.addAll(Arrays.asList(mColors));
        listHashMap.put("Color", list);
        return listHashMap;
    }
    
    }
    

    ConfigureCarAdapter.java:

    public class ConfigureCarAdapter extends BaseExpandableListAdapter {
    private Context context;
    private List<String> expandableListTitle;
    private HashMap<String, List<String>> expandableListDetail;
    public int[] checkedChildPosition;  // Save checked child position for each group.
    
    public ConfigureCarAdapter(Context context, List<String> expandableListTitle,
                                HashMap<String, List<String>> expandableListDetail) {
        this.context = context;
        this.expandableListTitle = expandableListTitle;
        this.expandableListDetail = expandableListDetail;
        checkedChildPosition = new int[expandableListTitle.size()];
        resetCheckedChildPosition(0);
    }
    
    @Override
    public String getChild(int listPosition, int expandedListPosition) {
        return this.expandableListDetail.get(this.expandableListTitle.get(listPosition)).get(expandedListPosition);
    }
    
    @Override
    public long getChildId(int listPosition, int expandedListPosition) {
        return expandedListPosition;
    }
    
    @Override
    public View getChildView(int listPosition, int expandedListPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        String expandedListText = getChild(listPosition, expandedListPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_item1, null);
        }
        CheckedTextView expandedListTextView = convertView.findViewById(R.id.expandedListItem);
        expandedListTextView.setText(expandedListText);
    
        // Checked the view if this child is checked.
        expandedListTextView.setChecked(checkedChildPosition[listPosition] == expandedListPosition);
        return convertView;
    }
    
    @Override
    public int getChildrenCount(int listPosition) {
        return this.expandableListDetail.get(this.expandableListTitle.get(listPosition)).size();
    }
    
    @Override
    public String getGroup(int listPosition) {
        return this.expandableListTitle.get(listPosition);
    }
    
    @Override
    public int getGroupCount() {
        return this.expandableListTitle.size();
    }
    
    @Override
    public long getGroupId(int listPosition) {
        return listPosition;
    }
    
    @Override
    public View getGroupView(int listPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        String listTitle = getGroup(listPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_group1, null);
        }
        TextView listTitleTextView = convertView.findViewById(R.id.listTitle);
        listTitleTextView.setTypeface(null, Typeface.BOLD);
        listTitleTextView.setText(listTitle);
    
        TextView selectedChild = convertView.findViewById(R.id.selectedChild);
        if(checkedChildPosition[listPosition] != -1){
            // if group have selected child, get child and display inside header.
            selectedChild.setText(getChild(listPosition, checkedChildPosition[listPosition]));
        }else{
            selectedChild.setText("");
        }
        return convertView;
    }
    
    @Override
    public boolean hasStableIds() {
        return false;
    }
    
    @Override
    public boolean isChildSelectable(int listPosition, int expandedListPosition) {
        return true;
    }
    
    // Reset checked childs starts from group "from" to last group.
    private void resetCheckedChildPosition(int from) {
        if(from < checkedChildPosition.length)
            for(int i=from; i<checkedChildPosition.length; i++) checkedChildPosition[i] = -1;
    }
    
    // Update adapter when a child is selected.
    public void updateWithChildSelected(int group, int child){
        resetCheckedChildPosition(group);
        checkedChildPosition[group] = child;
        notifyDataSetChanged();
    }
    
    }
    

    Hope it helps!