ExpandableListView expand only on a specific Button?
This is a bit old question, but this answer might help someone.
If you want to expand/collapse group by clicking on specific Button
or some other View
, you have to get that Button in getGroupView
method in your Adapter class. Then, in onClick
method of your Button
you have, either to cast parent
to ExpandableListView
, or to pass List's reference in constructor when you create adapter.
I prefer the first approach. Here's the code, assuming that you have one TextView
and an ImageView
that is the arrow. I've added changing the arrow state too.
@Overridepublic View getGroupView(final int groupPosition, final boolean isExpanded, View convertView, final ViewGroup parent) { String headerTitle = (String) getGroup(groupPosition); if (convertView == null) { LayoutInflater infalInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.left_drawer_list_group, parent, false); } TextView listHeaderText = (TextView) convertView .findViewById(R.id.left_menu_list_header_text); ImageView listHeaderArrow = (ImageView) convertView.findViewById(R.id.left_menu_list_header_arrow); listHeaderText.setText(headerTitle); //Set the arrow programatically, so we can control it int imageResourceId = isExpanded ? android.R.drawable.arrow_up_float : android.R.drawable.arrow_down_float; listHeaderArrow.setImageResource(imageResourceId); listHeaderArrow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isExpanded) ((ExpandableListView) parent).collapseGroup(groupPosition); else ((ExpandableListView) parent).expandGroup(groupPosition, true); } }); return convertView;}
Additionally, you would like to disable expanding/collapsing in onGroupClick
listener.
@Overridepublic boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { //Do some other stuff, but you shall not expand or collapse return true;}
There is another method, but the fairly bad one, and that is that you copy entire Adapter
class inside the class where you create ExpandableListView
and set Adapter
. But do not do that. Seriously! ;)
This is the onCreate from the ChannelList which extends ListFragment. It stores the data and generate a new Adapter if the Fragment is called.
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { m_ListView = new ExpandableListView(getActivity()); m_ListView.setId(android.R.id.list); m_ListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); m_ListView.setMultiChoiceModeListener(m_MultiChoiceModeListener); m_ChannelListAdapter = new ChannelListAdapter(getActivity(), this); m_ListView.setAdapter(m_ChannelListAdapter); m_ListView.setGroupIndicator(null); m_ListView.setOnGroupClickListener(this); return m_ListView;}
On the Adapter i have the getGroupView Method which look like:
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) { if (view == null) { view = inflater.inflate(R.layout.layout_channelwithimage, viewGroup, false); } TextView textView = (TextView) view.findViewById(R.id.labelwithimage); textView.setText(getGroup(i).toString()); ImageButton imbu = (ImageButton) view.findViewById(R.id.imageButton); //imbu.setOnClickListener(this); imbu.setFocusable(false); return view;}
So if i register the ImageButton in the adapter it will call the onClick from the adapter. But in the onClick i do not know which group was clicked... If i do not register the button on any listener it will not call the onGroupClick from the ChannelList...
Not overly elegant solution but it helped me out:
I've preserved the original groupIndicator. I liked the behavior as it was.
On the groupItem layout I simply blocked the space with empty view so that the original groupIndicator was still clickable:
<LinearLayout> ....<!--just dummy space underneath the default expand_collapse group icon - this way original expand collapse behavior is preserved on the icon--><View android:layout_width="25dp" android:layout_height="match_parent"></View><!-- text view will have actionListener --><TextView android:id="@+id/category_name" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" .... /> .... </LinearLayout>
Than sneaked in callBack object while creating ExpandableListAdapter and hooked it onClick on the "category_name" (for both child and group elements)
public class ExpandableListAdapter extends BaseExpandableListAdapter {public interface OnCategoryActionListener { boolean onCategorySelected(long categoryId);}....public ExpandableListAdapter(Activity context, Category rootCategory, OnCategoryActionListener callBack) { this.context = context; this.rootCategory = rootCategory; this.callBack = callBack;}....@Overridepublic View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { String categoryName = (String) getGroup(groupPosition); if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.category, null); } TextView item = (TextView) convertView.findViewById(R.id.category_name); item.setTypeface(null, Typeface.BOLD); item.setText(categoryName); item.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { callBack.onCategorySelected(getGroupId(groupPosition)); } }); .....
All you have to do now is to initialize properly ExpandableListAdapter in master fragment class
expListAdapter = new ExpandableListAdapter(getActivity(), this.rootCategory, new OnCategoryActionListener());expListView = (ExpandableListView) getActivity().findViewById(R.id.categories_list);expListView.setAdapter(expListAdapter);