I have searched for this issue a few days. Here's the structure of the app.
activity_main.xml:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- The main content view -->
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<fragment android:id="@+id/fragment_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="ca.bluecross.ab.view.fragments.DrawerFragment"
tools:layout="@layout/abc_drawer_layout" />
</android.support.v4.widget.DrawerLayout>
Here's the layout of the fragment (some elements are not included to save space for post):
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
android:layout_height="match_parent"
android:layout_width="fill_parent"
android:id="@+id/scrollView"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
..
/>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="2dp"
android:paddingBottom="5dp"
android:background="#21c1c1c1">
..
</RelativeLayout>
..
<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/expLVClaims"
/>
.
..
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TableRow
..
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content">
..
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content">
..
</TableRow>
</TableLayout>
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp">
<Button
android:layout_width="160dp"
android:layout_height="wrap_content"
android:text="I have more to add"
android:id="@+id/btnAddMoreClaim"
android:layout_gravity="center_horizontal"
android:layout_span="2"
android:layout_centerVertical="true"
android:layout_marginLeft="40dp"
android:background="@color/abc_blue"
android:textColor="#FFFFFF" />
<Button
android:layout_width="160dp"
android:layout_height="wrap_content"
android:text="I'm ready to submit"
android:id="@+id/btnReadyToSubmitClaim"
android:layout_span="2"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@+id/btnAddMoreClaim"
android:background="@color/abc_blue"
android:textColor="#FFF" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp">
<Button
android:layout_width="160dp"
android:layout_height="wrap_content"
android:text="Cancel"
android:id="@+id/btnCancelEnterClaim"
android:layout_alignWithParentIfMissing="false"
android:layout_centerInParent="true"
android:background="@color/abc_blue"
android:textColor="#FFF" />
</RelativeLayout>
</LinearLayout>
</ScrollView>
Here's the layout for group header:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:id="@+id/imgIndicator"
android:src="@drawable/icon_collapse"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Provider name"
android:id="@+id/txtProviderName"
android:layout_toRightOf="@+id/imgIndicator" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:id="@+id/imgDelete"
android:src="@drawable/icon_cross_delete"
android:layout_toLeftOf="@+id/imgEdit" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:id="@+id/imgEdit"
android:layout_alignParentEnd="true"
android:src="@drawable/icon_edit" />
</RelativeLayout>
Here's the child layout:
<?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"
android:background="#59868686">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:id="@+id/relativeLayoutServiceDate">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date of service"
android:id="@+id/txtClaimDetailServiceDateLabel"
android:layout_alignParentStart="true"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Feb 10, 2015"
android:id="@+id/txtClaimDetailServiceDate"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:id="@+id/relativeLayoutProvider">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Provider"
android:id="@+id/txtClaimDetailProviderLabel"
android:textStyle="bold"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="provider's name"
android:id="@+id/txtClaimDetailProviderName"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/relativeLayoutProduct">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Product or Service"
android:id="@+id/txtProductLabel"
android:textStyle="bold"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Product/service"
android:id="@+id/txtProduct"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:id="@+id/relativeLayoutClaimAmount">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Claim amount($)"
android:id="@+id/txtClaimDetailClaimAmountLabel"
android:textStyle="bold"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0.00"
android:id="@+id/txtClaimDetailClaimAmount"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:id="@+id/relativeLayoutOtherAmount">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Other amount($)"
android:id="@+id/txtClaimDetailOtherAmountLabel"
android:textStyle="bold"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0.00"
android:id="@+id/txtClaimDetailOtherAmount"
android:layout_alignParentEnd="true" />
</RelativeLayout>
</LinearLayout>
Here's the adapter for the ExpandableListView:
public class EclaimsExpandableListAdapter extends BaseExpandableListAdapter {
private ArrayList<ClaimGroup> groups;
public LayoutInflater inflater;
public Activity activity;
float mDensity;
private static final int MAX_ITEMS_MEASURED = 15;
public EclaimsExpandableListAdapter(Activity act, ArrayList<ClaimGroup> groups){
activity = act;
this.groups = groups;
inflater = act.getLayoutInflater();
mDensity = activity.getResources().getDisplayMetrics().density;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return groups.get(groupPosition).getChildren().get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
//return 0;
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
Log.d("EclaimsExpandableListAdapter :: getChildView() :: ", "Start");
ClaimDetail child = (ClaimDetail)getChild(groupPosition, childPosition);
if(convertView == null){
convertView = inflater.inflate(R.layout.eclaims_claim_detail_health_layout,null);
}
TextView txtServiceDate = (TextView)convertView.findViewById(R.id.txtClaimDetailServiceDate);
txtServiceDate.setText(child.getmServiceDate());
TextView txtProviderName = (TextView)convertView.findViewById(R.id.txtClaimDetailProviderName);
txtProviderName.setText(child.getProvider().getName());
TextView txtClaimAmount = (TextView)convertView.findViewById(R.id.txtClaimDetailClaimAmount);
txtClaimAmount.setText(child.getClaimAmount().toString());
TextView txtOtherAmout = (TextView)convertView.findViewById(R.id.txtClaimDetailOtherAmount);
if(child.getOtherAmount() == null){
txtOtherAmout.setVisibility(View.GONE);
}else{
txtOtherAmout.setText(child.getOtherAmount().toString());
}
return convertView;
}
@Override
public int getChildrenCount(int grpPostion) {
System.out.println("Group position :: " + grpPostion);
return groups.get(grpPostion).getChildren().size();
}
@Override
public Object getGroup(int groupPosition) {
return groups.get(groupPosition);
}
@Override
public int getGroupCount() {
return groups.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
Log.d("EclaimsExpandableListAdapter :: getGroupView() :: ", "Start");
if (convertView == null) {
convertView = inflater.inflate(R.layout.eclaims_claim_group_row, null);
}
/*TextView claimsLabel = (TextView)activity.findViewById(R.id.txtClaimItemsLabel);
if(groups.isEmpty()){
claimsLabel.setVisibility(View.GONE);
}else{
claimsLabel.setVisibility(View.VISIBLE);
}*/
ClaimGroup group = (ClaimGroup) getGroup(groupPosition);
ImageView indicator = (ImageView)convertView.findViewById(R.id.imgIndicator);
int nH = 0;
if(isExpanded){
indicator.setImageResource(R.drawable.icon_expand);
//nH = measureChildrenHeight(groupPosition);
}else{
indicator.setImageResource(R.drawable.icon_collapse);
//nH = convertView.getMeasuredHeight();
}
//parent.getLayoutParams().height = (int) (nH * mDensity);
//parent.invalidate();
TextView providerName = (TextView)convertView.findViewById(R.id.txtProviderName);
providerName.setText(group.getProvider().getName());
ImageView imgDelete = (ImageView)convertView.findViewById(R.id.imgDelete);
imgDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
String confirmation = activity.getString(R.string.eclaims_delete_claim_confirmation);
builder.setMessage(confirmation);
builder.setPositiveButton(R.string.alert_Cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Do nothing
}
});
builder.setNegativeButton(R.string.alert_OK, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
groups.remove(groupPosition);
notifyDataSetChanged();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
});
ImageView imgEdit = (ImageView)convertView.findViewById(R.id.imgEdit);
imgEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
String confirmation = activity.getString(R.string.eclaims_edit_claim_confirmation);
builder.setMessage(confirmation);
builder.setPositiveButton(R.string.alert_Cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Do nothing
}
});
builder.setNegativeButton(R.string.alert_OK, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// first: remove from the completed claims
Provider selectedProvider = ((ClaimGroup)getGroup(groupPosition)).getProvider();
ClaimGroup parent = groups.remove(groupPosition);
List<Product> prodList = parent.getProductList(); // retrieved the saved product list
ClaimDetail child = parent.getChildren().get(0); // there is only one child
Product selectedProduct = child.getProduct();
notifyDataSetChanged();
// second: populate the fields in claim detail block
TextView serviceDate = (TextView)activity.findViewById(R.id.txtServiceDate);
serviceDate.setText(child.getmServiceDate());
Spinner spinnerProvider = (Spinner)activity.findViewById(R.id.spinnerProviders);
ArrayAdapter<Provider> adapterProvider = (ArrayAdapter< Provider >)spinnerProvider.getAdapter();
int size = adapterProvider.getCount();
int pos_seletion = 0;
for(int i=0; i<size; i++){
Provider prvd = adapterProvider.getItem(i);
if(selectedProvider.equals(prvd)){
pos_seletion = i;
break;
}
}
System.out.println("Selected position for provider list :: " + pos_seletion);
spinnerProvider.setSelection(pos_seletion);
adapterProvider.notifyDataSetChanged();// do we need to notify?
Spinner spinnerProduct = (Spinner)activity.findViewById(R.id.spinnerProducts);
ArrayAdapter<Product> adapterProduct = (ArrayAdapter < Product >)spinnerProduct.getAdapter();
size = prodList.size();
pos_seletion = 0;
for(int j=0; j<size; j++){
Product prod = prodList.get(j);
if(selectedProduct.equals(prod)){
pos_seletion = j;
break;
}
}
System.out.println("Selected position for product list :: " + pos_seletion);
adapterProduct.clear();
adapterProduct.addAll(prodList);
spinnerProduct.setSelection(pos_seletion);
adapterProduct.notifyDataSetChanged(); // do we need to notify?
EditText claimAmt = (EditText)activity.findViewById(R.id.editClaimAmount);
claimAmt.setText(child.getClaimAmount().toString());
EditText otherAmt = (EditText)activity.findViewById(R.id.editOtherAmount);
if(child.getOtherAmount() != null){
otherAmt.setText(child.getOtherAmount().toString());
}
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
});
return convertView;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
@Override
public void onGroupCollapsed(int groupPosition) {
super.onGroupCollapsed(groupPosition);
}
@Override
public void onGroupExpanded(int groupPosition) {
super.onGroupExpanded(groupPosition);
}
}
Here's the behavior: when clicking the group header, no child view is displayed. From LogCat, I can see that getViewGroup()
in the adapter is called twice though, but getChildView()
is not called at all. After searching the internet and trying them out, I still can't get the child view displayed when clicking on the group header, but when I tried setting the ExpanandableListView
height with a fix height, say, 400dp, like this:
<ExpandableListView xmlns:
android:layout_width="match_parent"
android:layout_height="400dp"
android:id="@+id/expLVClaims"/>
the child view is then expanded and collapsed as expected. But the thing is that because the fixed height will makes the ExpandableListView
occupy 400dp space vertically, even no data is in the adapter at all, which is unwanted behavior.
Can someone throw some hints?
Thanks in advance! Shawn