I am tying to find a way to combine the group view and the child views in a list like this
except that it will be an expandable list instead.
Thank you.
I've taken the liberty to draw up some sample code for this. It made the most sense to just create your own custom view extending from ExpandableListView (especially if you want the rounded corners), a custom adapter to handle the groups and children, and then have your main.xml just include multiple custom views. As you can see from the screenshot, I've managed to reproduce it pretty closely.
So here's the code:
RoundedExpandableListView.java
public class RoundedExpandableListView extends ExpandableListView {
public RoundedExpandableListView(Context context) {
super(context);
}
public RoundedExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
// for setting the background color and rounded corners
int bgColor = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "background", 0xffffff);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.RoundedExpandableListView);
int radius = a.getInteger(R.styleable.RoundedExpandableListView_radius, 0);
PaintDrawable drawable = new PaintDrawable();
drawable.getPaint().setColor(bgColor);
drawable.setCornerRadius(radius);
setBackgroundDrawable(drawable);
a.recycle();
}
}
GroupedViewAdapter.java
public class GroupedViewAdapter extends BaseExpandableListAdapter {
private Context mContext;
private String[] mGroups;
private Object[][] mChildren;
private int mGroupLayoutId;
private int mChildLayoutId;
private Drawable mTitleDrawable;
public GroupedViewAdapter(Context c, String[] k, Object[][] v, int titleDrawableResId) {
this(c, k, android.R.layout.simple_expandable_list_item_1, v,
android.R.layout.simple_expandable_list_item_1, titleDrawableResId);
}
public GroupedViewAdapter(Context c, String[] k, int groupLayoutResId, Object[][] v,
int childLayoutResId, int titleDrawableResId) {
super();
mContext = c;
mGroups = k;
mChildren = v;
mGroupLayoutId = groupLayoutResId;
mChildLayoutId = childLayoutResId;
mTitleDrawable = mContext.getResources().getDrawable(titleDrawableResId);
mTitleDrawable.setBounds(0, 0, 48, 48); // not necessarily the best way, but just to show example
}
#Override
public int getGroupCount() {
return mGroups.length;
}
#Override
public int getChildrenCount(int groupPosition) {
return (mChildren[groupPosition] == null) ? 0 : mChildren[groupPosition].length;
}
#Override
public void onGroupCollapsed(int groupPosition) {
super.onGroupCollapsed(groupPosition);
}
#Override
public void onGroupExpanded(int groupPosition) {
super.onGroupExpanded(groupPosition);
}
#Override
public String getGroup(int groupPosition) {
return mGroups[groupPosition];
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return (mChildren[groupPosition] == null) ? null : mChildren[groupPosition][childPosition];
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
View v;
if (convertView != null) {
v = convertView;
} else {
LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(mGroupLayoutId, parent, false);
}
TextView tv = ((TextView) v);
tv.setText(getGroup(groupPosition));
tv.setTag(getGroupId(groupPosition));
// set title group special properties
if (groupPosition == 0) {
tv.setTextSize(20);
tv.setCompoundDrawables(mTitleDrawable, null, null, null);
} else if (isExpanded) {
tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_expanded, 0);
} else {
tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_collapsed, 0);
}
return tv;
}
#Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
View v;
if (convertView != null) {
v = convertView;
} else {
LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(mChildLayoutId, parent, false);
}
TextView tv = ((TextView) v);
tv.setText((String)getChild(groupPosition, childPosition));
tv.setTag(getChildId(groupPosition, childPosition));
return tv;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
MainActivity.java
public class MainActivity extends Activity {
private RoundedExpandableListView mContact;
private RoundedExpandableListView mAddress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContact = (RoundedExpandableListView) findViewById(R.id.listview_contact);
mAddress = (RoundedExpandableListView) findViewById(R.id.listview_address);
mContact.setAdapter(new GroupedViewAdapter(this,
getResources().getStringArray(R.array.contact_list_items), // I chose to create this directly in XML, but you can generate it via Java like I did the children below
R.layout.drawer_list_item,
createChildList(),
R.layout.drawer_list_item,
R.drawable.ic_action_email));
mAddress.setAdapter(new GroupedViewAdapter(this,
getResources().getStringArray(R.array.address_list_items),
R.layout.drawer_list_item,
createChildList(),
R.layout.drawer_list_item,
R.drawable.ic_action_map));
mContact.setGroupIndicator(null); // since the adapter is changing how to show the group indicator icon
mAddress.setGroupIndicator(null); // since the adapter is changing how to show the group indicator icon
}
private String[][] createChildList() {
// Do stuff here to generate the list of children. Since the examples
// didn't have any, I didn't add any here.
return null; // Change this once you have children
}
}
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res/com.example.sample"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#95c91d" >
<com.example.sample.RoundedExpandableListView
android:id="#+id/listview_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginBottom="20dp"
android:paddingLeft="10dp"
android:background="#ffffff"
local:radius="20" />
<com.example.sample.RoundedExpandableListView
android:id="#+id/listview_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginBottom="20dp"
android:paddingLeft="10dp"
android:background="#ffffff"
local:radius="20"
android:layout_below="#+id/listview_contact" />
</RelativeLayout>
res/layout/drawer_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/list_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textSize="14sp"
android:text="test"
android:paddingTop="#dimen/list_item_margin"
android:paddingRight="#dimen/list_item_margin"
android:paddingBottom="#dimen/list_item_margin"
android:drawableLeft="#android:drawable/ic_menu_manage"
android:drawablePadding="12dp"
/>
res/values/attrs.xml (for creating custom attributes for your View)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RoundedExpandableListView">
<attr name="radius" format="integer" />
</declare-styleable>
</resources>
res/values/strings.xml
<!-- stuff up here -->
<string-array name="contact_list_items">
<item name="item_title">Contact</item>
<item name="item_number">+41 41 41</item>
<item name="item_email">xxx#email.com</item>
<item name="item_website">www.website.com</item>
</string-array>
<string-array name="address_list_items">
<item name="item_title">Address</item>
<item name="item_address">xxxxxx\nxxxxxxxxxxx\nxxxxxxxxxx\nxxxxxxx</item>
<item name="item_other">PDF</item>
</string-array>
That should be it! Good luck!
Related
I'm implementing an ExpandableListView within a LinearLayout, but when I run the app, I get this:
Firstly, is this normal that the header appears twice?
When I click on the upper header, I get the expanded view which is how I want it to be:
If I touch the second header (that, in my opinion, is not supposed to exist), it disppears, letting the upper header alone (like I want it to be):
BUT the expandable height has changed!:
I don't know why this happens. I'd like to have just one header, and I want the size to be fixed. Here are the files with the relevant code:
The layout where the ExpandableListView is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main_sv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/white" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp" >
...
<ExpandableListView
android:id="#+id/learnabletm"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
</LinearLayout>
expandable_list_view_child.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="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/child"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="17dip"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft" />
</LinearLayout>
expandable_list_view_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"
android:padding="8dp">
<TextView
android:id="#+id/group"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
android:textSize="18dp" />
</LinearLayout>
ExpAdapter.java
public class ExpAdapter extends BaseExpandableListAdapter {
public static final String ARG_POS = "pos";
private Context myContext;
Bundle data;
publicExpAdapter(Context context, Bundle data) {
myContext = context;
this.data = data;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
#Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.expandable_list_view_child, null);
}
String text = "";
for(int i = 0; i < bytes.length; i++){
for(int j = 0; j < 8; j++){
text = text + " " + (i*8+j+1) + "\n";
}
}
TextView child = (TextView) convertView.findViewById(R.id.child);
child.setText(text);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return 1;
}
#Override
public Object getGroup(int groupPosition) {
return null;
}
#Override
public int getGroupCount() {
return 1;
}
#Override
public long getGroupId(int groupPosition) {
return 0;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.expandable_list_view_group, null);
}
TextView group = (TextView) convertView.findViewById(R.id.group);
group.setText("Numbers");
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
}
And finally the fragment where the ExpandableListView is called:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
expList = (ExpandableListView) rootView.findViewById(R.id.learnabletm);
width = args.getInt(ARG_WIDTH);
expList.setIndicatorBounds(width - GetDipsFromPixel(50), width - GetDipsFromPixel(10));
expList.setAdapter(new ExpAdapter(getActivity(), data));
expList.expandGroup(ExpandableListView.PACKED_POSITION_TYPE_CHILD);
expList.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener(){
#Override
public void onGroupExpand(int groupPosition){
LinearLayout.LayoutParams param = (LinearLayout.LayoutParams) expList.getLayoutParams();
param.height = expList.getHeight();
expList.setLayoutParams(param);
expList.refreshDrawableState();
}
});
expList.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener(){
#Override
public void onGroupCollapse(int groupPosition){
LinearLayout.LayoutParams param = (LinearLayout.LayoutParams) expList.getLayoutParams();
param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
expList.setLayoutParams(param);
expList.refreshDrawableState();
}
});
expList.setOnChildClickListener(new ExpandableListView.OnChildClickListener(){
#Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id){
Log.d("OnChildClickListener", "OK");
return false;
}
});
}
I am using Expandable ListView example found on net
Activity:
public class ExpandableListViewActivity extends ExpandableListActivity {
/**
* strings for group elements
*/
static final String arrGroupelements[] = { "India", "Australia", "England",
"South Africa" };
/**
* strings for child elements
*/
static final String arrChildelements[][] = {
{ "Sachin Tendulkar", "Raina", "Dhoni", "Yuvi" },
{ "Ponting", "Adam Gilchrist", "Michael Clarke" },
{ "Andrew Strauss", "kevin Peterson", "Nasser Hussain" },
{ "Graeme Smith", "AB de villiers", "Jacques Kallis" } };
DisplayMetrics metrics;
int width;
ExpandableListView expList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
expList = getExpandableListView();
metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
width = metrics.widthPixels;
// this code for adjusting the group indicator into right side of the
// view
expList.setIndicatorBounds(width - GetDipsFromPixel(50), width
- GetDipsFromPixel(10));
expList.setAdapter(new ExpAdapter(this));
expList.setOnGroupExpandListener(new OnGroupExpandListener() {
public void onGroupExpand(int groupPosition) {
Log.e("onGroupExpand", "OK");
}
});
expList.setOnGroupCollapseListener(new OnGroupCollapseListener() {
public void onGroupCollapse(int groupPosition) {
Log.e("onGroupCollapse", "OK");
}
});
expList.setOnChildClickListener(new OnChildClickListener() {
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
Log.e("OnChildClickListener", "OK");
return false;
}
});
}
public int GetDipsFromPixel(float pixels) {
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (pixels * scale + 0.5f);
}
}
Adapter:
public class ExpAdapter extends BaseExpandableListAdapter {
private Context myContext;
public ExpAdapter(Context context) {
myContext = context;
}
public Object getChild(int groupPosition, int childPosition) {
return null;
}
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) myContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.child_row, null);
}
TextView tvPlayerName = (TextView) convertView
.findViewById(R.id.tvPlayerName);
tvPlayerName
.setText(ExpandableListViewActivity.arrChildelements[groupPosition][childPosition]);
return convertView;
}
public int getChildrenCount(int groupPosition) {
return ExpandableListViewActivity.arrChildelements[groupPosition].length;
}
public Object getGroup(int groupPosition) {
return null;
}
public int getGroupCount() {
return ExpandableListViewActivity.arrGroupelements.length;
}
public long getGroupId(int groupPosition) {
return 0;
}
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) myContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.group_row, null);
}
TextView tvGroupName = (TextView) convertView
.findViewById(R.id.tvGroupName);
tvGroupName
.setText(ExpandableListViewActivity.arrGroupelements[groupPosition]);
return convertView;
}
public boolean hasStableIds() {
return false;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
main.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="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:groupIndicator="#drawable/group_indicator" >
<TextView
android:id="#+id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="No Items" >
</TextView>
</ExpandableListView>
</LinearLayout>
I tried this solution, but didn't work :(
Android: Custom ListAdapter extending BaseAdapter crashes on application launch
there its told to add a third parameter "false", to the inflater.inflate(R.layout.group_row, null, false);
Move the TextView outside the ExpandableListView element:
<?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="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:groupIndicator="#drawable/group_indicator" >
</ExpandableListView>
<TextView
android:id="#+id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="No Items" >
</TextView>
</LinearLayout>
Subclasses of AdapterView(like ExpandableListView) can't have children in a xml layout(like you did in your layout).
If you're like me and found this question without using ExpandableListView, try using adding the third parameter to the inflate method, as #Luksprog mentions, also mentioned here:
inflater.inflate(R.layout.group_row, parent, false);
Don't use true instead of false or you will get the same error that brought you here, because it's trying to attach/add it to the parent, hence the addView is not supported in AdapterView error.
I can't for the life of me figure out why my ExpandableListView doesn't expand... I have used log statements in just about every click listener I can find for the ExpandableListView and it doesnt look like any of them get called.
I know there are many posts on this topic but I have read through them all and tried many things and am having no luck, hopefully I'm missing some tiny error that will be easy to spot for someone else.
Main Activity:
public class ForumListActivity extends Activity {
private static ArrayList<Forum> forumList;
private static ArrayList<ArrayList<SubForum>> subForumList;
private ExpandableListView forumListView;
private ForumListAdapter forumListAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main_page);
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
forumListView = (ExpandableListView) this.findViewById(R.id.main_page_forum_list);
forumList = new ArrayList<Forum>();
subForumList = new ArrayList<ArrayList<SubForum>>();
setUpForums(this);
forumListAdapter = new ForumListAdapter(this, forumList, subForumList);
forumListView.setAdapter(forumListAdapter);
forumListView.setOnGroupExpandListener(new OnGroupExpandListener(){
#Override
public void onGroupExpand(int groupPosition) {
Log.d("onGroupExpand", "this works?");
for(int i=0; i<forumListAdapter.getGroupCount(); i++) {
if(i != groupPosition)
forumListView.collapseGroup(groupPosition);
}
}
});
forumListView.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Log.d("onGroupClick:", "worked");
parent.expandGroup(groupPosition);
return true;
}
});
}
Note: the method setUpForums() just takes system arrays and puts them into forumList and subForumList
ListViewAdapter:
public class ForumListAdapter extends BaseExpandableListAdapter {
private ArrayList<Forum> groups;
private ArrayList<ArrayList<SubForum>> children;
private Context ctx;
public ForumListAdapter(Context ctx, ArrayList<Forum> groups, ArrayList<ArrayList<SubForum>> children) {
this.ctx = ctx;
this.groups = groups;
this.children = children;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return children.get(groupPosition).get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(ctx);
convertView = inflater.inflate(R.layout.forum_list_child_item_row, null);
}
SubForum currentSubForum = children.get(groupPosition).get(childPosition);
TextView name = (TextView)convertView.findViewById(R.id.child_row_forum_title);
TextView desc = (TextView)convertView.findViewById(R.id.child_row_forum_description);
if (name != null)
name.setText(currentSubForum.getName());
if (desc != null)
desc.setText(currentSubForum.getDescription());
convertView.setFocusableInTouchMode(true);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return children.get(groupPosition).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(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
if (convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(ctx);
convertView = inflater.inflate(R.layout.forum_list_group_item_row, null);
}
Forum currentForum = (Forum) groups.get(groupPosition);
TextView name = (TextView) convertView.findViewById(R.id.group_item_forum_title);
//ImageView image = (ImageView) convertView.findViewById(R.id.group_item_expander_image);
if(name != null)
name.setText(currentForum.getName());
/*
if(image != null) {
int[][] group_state_sets = {{}, {android.R.attr.state_expanded}};
image.setVisibility(View.VISIBLE);
int stateSetIndex = (isExpanded ? 1 : 0) ;
Drawable drawable = image.getDrawable();
drawable.setState(group_state_sets[stateSetIndex]);
}
*/
return convertView;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
Group Layout:
<?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="fill_parent"
android:background="#drawable/turquoise_gradient"
android:orientation="horizontal"
android:paddingTop="6dip"
android:paddingBottom="6dip"
android:paddingLeft="6dip" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/turquoise_gradient"
android:orientation="vertical"
android:padding="2dip" >
<TextView
android:id="#+id/group_item_forum_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|left"
android:gravity="left"
android:paddingLeft="5dip"
android:textColor="#color/white"
android:textSize="16dip" />
</LinearLayout>
<!--
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="center|right">
<ImageView
android:id="#+id/group_item_expander_image"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/collapse_down" />
</LinearLayout> -->
</LinearLayout>
child layout:
<?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="fill_parent"
android:background="#drawable/turquoise_gradient"
android:orientation="horizontal"
android:paddingTop="6dip"
android:paddingBottom="6dip"
android:paddingLeft="6dip" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="2dip"
android:background="#drawable/turquoise_gradient" >
<TextView
android:id="#+id/child_row_forum_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:layout_gravity="center_vertical"
android:paddingLeft="5dip"
android:textColor="#color/white"
android:maxLines="1"
android:textSize="11dip" />
<TextView
android:id="#+id/child_row_forum_description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:layout_gravity="center_vertical"
android:paddingLeft="15dip"
android:textColor="#color/white"
android:maxLines="2"
android:textSize="11dip" />
</LinearLayout>
</LinearLayout>
main page layout:
<?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="fill_parent"
android:background="#color/black"
android:orientation="vertical" >
<ExpandableListView
android:id="#+id/main_page_forum_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/black"
android:divider="#color/black"
android:dividerHeight="1dip"
android:clickable="true" />
</LinearLayout>
Any help you can provide is greatly appreciated!
I've also encountered similar problem like you. After a couple of days of investigation, I found that I did something wrong. So I fixed it to work correctly by making small change.
Let's look at the body of boolean onGroupClick(...) in setOnGroupClickListener. You've returned true that means "the click was handled"
You should return false if you want to expand. So I suggest you to do like this :
forumListView.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Log.d("onGroupClick:", "worked");
parent.expandGroup(groupPosition);
return false;
}
});
in android.widget.ExpandableListView class, there is a method named boolean handleItemClick(View v, int position, long id) which is responsible for expanding/collapsing groups or passing on the click to the proper child.
/* It's a group click, so pass on event */
if (mOnGroupClickListener != null) {
if (mOnGroupClickListener.onGroupClick(this, v,
posMetadata.position.groupPos, id)) {
posMetadata.recycle();
return true;
}
}
/* expanding/collapsing/other tasks... */
if you implement onGroupClick to return true, the the code below 8th line will never be executed. (that means, groups will never be collapsed, expanded)
Hope my answer helped you :-) good luck!
In case you have a widget on your list item, such as a Button, you may have to add android:focusable="false" to it. The Button was not allowing my list item to be clicked. That was the issue in my case.
There are probably three things u need to check,
check if u have any data available for the chid, cos if u dont have any data the child will not appear at all.
2.try removing if condition check while you using layout inflaters
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(ctx);
convertView = inflater.inflate(R.layout.forum_list_child_item_row, null);
}
you need to also pass Viewgroup here
convertView = inflater.inflate(R.layout.forum_list_child_item_row,parent, false);
I know this was already answered, but try setting the base layout of whatever you're inflating to have the attribute:
android:descendantFocusability="blocksDescendants"
If your expandable listview parent has button or switch it doesn't get called i wasted whole day in this.
So just use below code
android:focusable="false"
android:focusableInTouchMode="false"
Add this code inside toggle button,switch button or any which is on expandable listview
Make sure your custom group layout does not have android:textIsSelectable="false" as "true", if the text in textview is set to selectable, the expandable listview would expand in gingerbread but not in jellybean and might not work in ICS too.
I had a similar problem and it was solved by removing the android:clickable="true" property from ExpandableListView on xml.
When you are working with expandable lists then group expand is default functionality in it . means that group will expand itself only when you click on it you donot need to overrirde onGroupExpand(int groupPosition) or any other method just simply populate your data into your list somthing like this:
public class MyActivity extends Activity {
private ExpandableListView forumListView;
private ForumListAdapter forumListAdapter;
String[] forumList={"group 1","group 2","group 3"};
String[][] subForumList={{"group 1 child1","group 1 child1","group 1 child3"},
{"group 2 child1","group 2 child2","group 2 child3"},
{"group 3 child1","group 3 child2","group 3 child3"},
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
forumListView = (ExpandableListView) this.findViewById(R.id.main_page_forum_list);
forumListAdapter = new ForumListAdapter(this, forumList, subForumList);
forumListView.setAdapter(forumListAdapter);
/* forumListView.setOnGroupExpandListener(new OnGroupExpandListener(){
public void onGroupExpand(int groupPosition) {
Log.d("onGroupExpand", "this shit works?");
for(int i=0; i<forumListAdapter.getGroupCount(); i++) {
if(i != groupPosition)
forumListView.collapseGroup(groupPosition);
}
}
});
forumListView.setOnGroupClickListener(new OnGroupClickListener() {
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Log.d("onGroupClick:", "worked");
parent.expandGroup(groupPosition);
return true;
}
});*/
}
public class ForumListAdapter extends BaseExpandableListAdapter {
String[] groups;
String[][] children;
private Context ctx;
public ForumListAdapter(Context ctx, String[] groups, String[][] children) {
this.ctx = ctx;
this.groups = groups;
this.children = children;
}
public Object getChild(int arg0, int arg1) {
// TODO Auto-generated method stub
return children[arg0][arg1];
}
public long getChildId(int arg0, int arg1) {
// TODO Auto-generated method stub
return arg1;
}
public View getChildView(int arg0, int arg1, boolean arg2, View arg3,
ViewGroup arg4) {
if (arg3 == null) {
LayoutInflater inflater = LayoutInflater.from(ctx);
arg3 = inflater.inflate(R.layout.child, null);
}
String childData = children[arg0][arg1];
TextView name = (TextView)arg3.findViewById(R.id.child_row_forum_title);
TextView desc = (TextView)arg3.findViewById(R.id.child_row_forum_description);
if (name != null)
name.setText(childData);
if (desc != null)
// desc.setText(currentSubForum.getDescription());
arg3.setFocusableInTouchMode(true);
return arg3;}
public int getChildrenCount(int arg0) {
// TODO Auto-generated method stub
return children[arg0].length;
}
public Object getGroup(int arg0) {
// TODO Auto-generated method stub
return groups[arg0];
}
public int getGroupCount() {
// TODO Auto-generated method stub
return groups.length;
}
public long getGroupId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
public View getGroupView(int arg0, boolean arg1, View arg2, ViewGroup arg3) {
if (arg2 == null)
{
LayoutInflater inflater = LayoutInflater.from(ctx);
arg2 = inflater.inflate(R.layout.group, null);
}
TextView name = (TextView) arg2.findViewById(R.id.group_item_forum_title);
//ImageView image = (ImageView) arg2.findViewById(R.id.group_item_expander_image);
if(name != null)
name.setText(groups[arg0]);
/*
if(image != null) {
int[][] group_state_sets = {{}, {android.R.attr.state_expanded}};
image.setVisibility(View.VISIBLE);
int stateSetIndex = (isExpanded ? 1 : 0) ;
Drawable drawable = image.getDrawable();
drawable.setState(group_state_sets[stateSetIndex]);
}
*/
return arg2;}
public boolean hasStableIds() {
// TODO Auto-generated method stub
return false;
}
public boolean isChildSelectable(int arg0, int arg1) {
// TODO Auto-generated method stub
return false;
}
}
}
forumListView.collapseGroup(groupPosition);
should be
forumListView.collapseGroup(i);
Add implements OnGroupExpandListener to your Activity. Then It will works. I am Using same it works fine.
In my case I had buttons in group and child views and even setting android:focusable="false"
android:focusableInTouchMode="false" on both it didn't work.
So I had to change them from ImageButton to ImageView. The listeners for the clicks are the same. You might need to create a custom background to give the touch animation for the ImageView.
I need an ExpandableList in my Android app. By extending ExpandableListActivity whose content view is as the following:
<?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="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="#id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:id="#+id/tv_add"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/txt_add" />
</LinearLayout>
and extending BaseExpandableListAdapter I am now able to display data of groups and children in a TextView.
However, I want to customize the view of children. How may I be able to do so through another xml file?
EDIT:
Here's my row.xml for the view of children:
<?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="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/title"
android:textSize="16sp"
android:textStyle="bold"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
/>
<TextView
android:id="#+id/description"
android:textSize="10sp"
android:textStyle="normal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
/>
</LinearLayout>
Create two layout xml files for Group and Child views respectively -
For example, *group_layout.xml* and *child_layout.xml*
These layouts are inflated and used in the custom ExpandableListAdapter as shown below.
You can customize the Adapter class and set that adapter to the ExpandableListView.
public class SampleActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState)
{
ExpandableListView listView = (ExpandableListView) findViewById(R.id.listView);
ExpandableListAdapter adapter = new ExpandableListAdapter(this, new ArrayList<String>(), new ArrayList<ArrayList<Vehicle>>());
// Set this adapter to the list view
listView.setAdapter(adapter);
}
}
Custom Adapter class can be created as shown below:
class ExpandableListAdapter extends BaseExpandableListAdapter {
public ExpandableListAdapter(Context context, ArrayList<String> groups,
ArrayList<ArrayList<Vehicle>> children) {
this.context = context;
this.groups = groups;
this.children = children;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return children.get(groupPosition).get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
// Return a child view. You can load your custom layout here.
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
Vehicle vehicle = (Vehicle) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.child_layout, null);
}
TextView tv = (TextView) convertView.findViewById(R.id.tvChild);
tv.setText(" " + vehicle.getName());
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return children.get(groupPosition).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;
}
// Return a group view. You can load your custom layout here.
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
String group = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.group_layout, null);
}
TextView tv = (TextView) convertView.findViewById(R.id.tvGroup);
tv.setText(group);
return convertView;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public boolean isChildSelectable(int arg0, int arg1) {
return true;
}
}
Hope this helps you.
Thx to PRC, but according to my row.xml, the correct version of getChildView would be
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
LinearLayout layout;
Vehicle vehicle = (Vehicle) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (LinearLayout) infalInflater.inflate(R.layout.child_layout, null);
}
TextView tv = (TextView) convertView.findViewById(R.id.tvChild);
tv.setText(" " + vehicle.getName());
return layout;
}
I'm trying to write a simple example which pulls external data over the network and populates an ExpandableListView via a ExpandableListAdapter. I've tried a couple examples and am pretty much lost. I'm familiar with working with the ArrayAdapter class, but it seems that ExpandableListAdapter is WAY different. Here is my current application code that is displaying nothing:
MyExpandableListAdapter:
public class MyExpandableListAdapter extends BaseExpandableListAdapter {
public static class GroupHolder {
TextView title;
}
public static class ChildHolder {
TextView title;
ImageView icon;
}
// groups.getChildren() returns the children
private List<Group> groups;
private Context context;
private LayoutInflater inflater;
public MyExpandableListAdapter(Context context, List<Group> groups) {
this.context = context;
this.groups = groups;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public boolean hasStableIds() {
return true;
}
public Object getGroup(int groupPosition) {
return groups.get(groupPosition);
}
public int getGroupCount() {
return groups.size();
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
GroupHolder holder;
if (convertView != null) {
holder = (GroupHolder)convertView.getTag();
} else {
convertView = inflater.inflate(R.layout.group_item, parent, false);
holder = new GroupHolder();
holder.title = (TextView) convertView.findViewById(R.id.group_item_title);
convertView.setTag(holder);
}
holder.title.setText(this.groups.get(groupPosition).getName());
return convertView;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public Object getChild(int groupPosition, int childPosition) {
return groups.get(groupPosition).getChildren().get(childPosition);
}
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
public int getChildrenCount(int groupPosition) {
return groups.get(groupPosition).getChildren().size();
}
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder holder;
if (convertView != null) {
holder = (ChildHolder) convertView.getTag();
} else {
convertView = inflater.inflate(R.layout.child_item, parent, false);
holder = new ChildHolder();
holder.title = (TextView) convertView.findViewById(R.id.child_item_title);
holder.icon = (ImageView) convertView.findViewById(R.id.child_item_icon);
convertView.setTag(holder);
}
holder.title.setText(groups.get(groupPosition).getChildren().get(childPosition).getName());
// TODO add in image loading.
return convertView;
}
}
MyExpandableListActivity:
public class MyExpandableListActivity extends ExpandableListActivity {
private List<Group> groups;
private ExpandableListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.group_list);
this.groups = new ArrayList<Group>();
Group group = new Group("$1", "Colors");
Child child = new Child("$2", "Red");
groups.getChildren().add(child);
this.adapter = new MyExpandableListAdapter(this, groups);
setListAdapter(this.adapter);
}
}
R.layout.group_list:
<?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="fill_parent">
<ExpandableListView android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<TextView android:id="#+id/android:empty"
android:text="EMPTY! DOOM!"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
R.layout.group_item:
<?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="match_parent">
<TextView android:id="#+id/group_item_title"/>
</LinearLayout>
R.layout.child_item:
<?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="match_parent"
android:orientation="horizontal">
<ImageView android:id="#+id/child_item_icon"
android:layout_width="48px" android:layout_height="48px"/>
<TextView android:id="#+id/child_item_title"/>
</LinearLayout>
I, of course, am seeing "EMPTY! DOOM!" rather than the list item I added in my activity. What am I doing wrong?
Also, it seems that the SimpleExpandableListAdapter is supposed to make things easy, but I totally can't figure out how it works or how to use it. Can anyone help me figure this out?
I got bit this week with two items trying to use "fill_parent" at the same time and in the same space. It's possible your list is being shoved to the back or off screen. I see you have a simlar setup in your group_list layout. Hope that helps with the invisible list piece.
What about changing the LinearLayout to have a vertical orientation in your group_list.xml?
It doesn't quite match the layout given in the ExpandableListActivity docs.
You can also set breakpoints in places like your getView() method and see if it's being called at all.