Question

I have expandable list which looks like this:

enter image description here

Orange items are children and are shown when you press specific parent. Blue items are parents.I used this custom adapter to create this: (I picked this source code somewhere here on forum)

public class ExpandableListAdapter extends BaseExpandableListAdapter {

private Context context;
private List<String> listDataHeader;
private HashMap<String, List<String>> listDataChild;

public ExpandableListAdapter(Context context, List<String> listDataHeader,
        HashMap<String, List<String>> listChildData) {
    this.context = context;
    this.listDataHeader = listDataHeader;
    this.listDataChild = listChildData;
}

@Override
public Object getChild(int groupPosition, int childPosititon) {
    return this.listDataChild.get(this.listDataHeader.get(groupPosition))
            .get(childPosititon);
}

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

@Override
public View getChildView(int groupPosition, final int childPosition,
        boolean isLastChild, View convertView, ViewGroup parent) {

    final String childText = (String) getChild(groupPosition, childPosition);

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

    TextView txtListChild = (TextView) convertView
            .findViewById(R.id.lblListItem);

    txtListChild.setText(childText);
    return convertView;
}

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

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

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

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

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

    TextView lblListHeader = (TextView) convertView
            .findViewById(R.id.lblListHeader);
    lblListHeader.setTypeface(null, Typeface.BOLD);
    lblListHeader.setText(headerTitle);
    return convertView;
}

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

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

}

these are xml files:

list_item.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="55dip"
android:orientation="vertical" >

<TextView
    android:id="@+id/lblListItem"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:gravity="center_vertical"
    android:maxLines="1"
    android:background="@drawable/border_orange"
    android:paddingBottom="5dp"
    android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
    android:paddingTop="5dp"
    android:textColor="#f95001"
    android:textSize="18sp" />

</LinearLayout>

list_group.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" >

<TextView
    android:id="@+id/lblListHeader"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:background="@drawable/border"
    android:gravity="center_vertical"
    android:maxLines="1"
    android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
    android:textColor="#1e90ff"
    android:textSize="16sp" />

 </LinearLayout>

this is how i specified actual list:

<ExpandableListView
    android:id="@+id/all_songs"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentTop="true"
    android:choiceMode="singleChoice"
    android:listSelector="@layout/selector_list_item" >
</ExpandableListView>

and this is selector for button press:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
   android:exitFadeDuration="@android:integer/config_mediumAnimTime">

   <item android:drawable="@android:color/holo_blue_bright" android:state_pressed="true"/>
   <item android:drawable="@android:color/holo_blue_light" android:state_selected="true"/>
   <item android:drawable="@android:color/holo_blue_dark" android:state_activated="true"/>

</selector>

Recently i changed how the whole app will look, and before i added these borders on items in list everything was fine. But now i want to change how selector behaves for group items (still use rectangular shape), and different for children (use some kind of oval to fill this orange oval and not whole rectangle of list item)

How can i achieve this? I think i could manage to make xml drawables with shapes to put on selector but how can i separate parent and child selector?

EDIT: if you need any other source code, please leave comment.

Progress:

With help of @Omar i managed to create this code which works for group selector. (But it is kind of stupid to use two threads to achieve effect of selector disappearing, and i had to access it through static reference in activity)

//inside getGroupView() method

if (MusicPlayerActivity.all_songs != null) {
        if (isExpanded) {
            MusicPlayerActivity.all_songs
                    .setSelector(R.drawable.child_selector);
        } else {
            MusicPlayerActivity.all_songs
                    .setSelector(R.drawable.group_selector);
        }
        if (MusicPlayerActivity.all_songs != null)
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {e.printStackTrace();
                    }
                    if (MusicPlayerActivity.all_songs != null)
                        MusicPlayerActivity.act
                                .runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        MusicPlayerActivity.all_songs
                                                .setSelector(R.drawable.transparent);
                                    }
                                });
                }
            }.start();
    }

I also figured out that this progress could be achieved by modifying first item in selector xml (above). So is there any way to specify child selector in that xml for selector?

Was it helpful?

Solution

Try doing the following,

  • Add a hashmap of children states(Selected or not selected)

    private HashMap> listDataChildStates;

  • In your adapter constructor, add the following code:

    // Initially, set all child items as not selected
    for(int i = 0;i<listDataHeader.size();i++)
    {
        ArrayList<String> childItems = listChildData.get(listDataHeader.get(i));
        ArrayList<Boolean> childStates;
        for(int j = 0;j<childItems.size();j++)
        {
                childStates = listDataChildStates.get(childItems.get(j));
                if(childStates == null)
                    childStates = new ArrayList<Boolean>();
                childStates.add(false);
        }
    }
    
  • Then, in your onChildClickListener()

    expListView.setOnChildClickListener(new OnChildClickListener() {

            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                    int groupPosition, int childPosition, long id) {
                    boolean childState = listDataChildStates.get(listDataHeader.get(groupPosition)).get(childPosition);
      listDataChildStates.get(listDataHeader.get(groupPosition)).remove(childPosition);
      listDataChildStates.get(listDataHeader.get(groupPosition)).add(childPosition,new Boolean(!childState));
    
                 notifyDataSetChanged();
                 return false;
            }
        });
    
  • Finally, in your getChildView() method, add the following:

     boolean childState = listDataChildStates.get(listDataHeader.get(groupPosition)).get(childPosition);
     if(childState)
     {
             // Set your child item as selected
     }else
     {
            // Set your child item as not selected
     }
    

OTHER TIPS

have you tried like this ?

getChildView(int groupPosition, final int childPosition,
    boolean isLastChild, View convertView, ViewGroup parent) {

final String childText = (String) getChild(groupPosition, childPosition);

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

TextView txtListChild = (TextView) convertView
        .findViewById(R.id.lblListItem);

txtListChild.setText(childText);

*convertView.setBackgroundDrawable(some drawable for view from drawable resourse)
return convertView;

}

I think this whould be direct way.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top