I'm right now trying to set up an ExpandableListView inside my fragment with following behaviour. I have three Groups with CheckedTextViews:
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
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!
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!