我一直在试图做到这一点的问题。我似乎无法得到它的权利,我想控制每个父母+孩子的父母。 ExpandableListView已经让我头疼。包意见;
公共类CommentsExpandableListAdapter扩展BaseExpandableListAdapter {私人活动范围内;私人地图<字符串列表<串GT;> comments_feed_collection;私人列表<串GT; GROUP_LIST;私人布尔a_comment = FALSE;公共CommentsExpandableListAdapter(Activity上下文,列表<串GT; group_list中, 地图<字符串列表<串GT;> comments_feed_collection){ this.context =背景; this.comments_feed_collection = comments_feed_collection; this.group_list = GROUP_LIST;}公共对象getChild(INT groupPosition,诠释childPosition){ 返回comments_feed_collection.get(group_list.get(groupPosition))获得(childPosition)。}众长getChildId(INT groupPosition,诠释childPosition){ 返回childPosition;}公共查看getChildView(最终诠释groupPosition,最终诠释childPosition, 布尔isLastChild,查看convertView,父母的ViewGroup){ 最后弦乐incoming_text =(字符串)getChild(groupPosition,childPosition); LayoutInflater吹气= context.getLayoutInflater(); 如果(convertView == NULL){ //第一个视图 如果(childPosition == 0安培;&安培; groupPosition == 0){ convertView = inflater.inflate(R.layout.description_of_ads_expandable_list,NULL); TextView的description_child =(TextView中)convertView.findViewById(R.id.description_of_ads_expandable_list_child_text_view); description_child.setText(incoming_text); }否则如果(childPosition == 0安培;&安培; groupPosition == 1){ //第二种观点认为 convertView = inflater.inflate(R.layout.comments_create_comment,NULL); }否则如果(childPosition> = 1和;&放大器; groupPosition> = 1){ // THRID视图 convertView = inflater.inflate(R.layout.comments_expandable_list_child,NULL); } } 返回convertView;}公众诠释getChildrenCount(INT groupPosition){ 返回comments_feed_collection.get(group_list.get(groupPosition))的大小()。}公共对象getGroup(INT groupPosition){ 返回group_list.get(groupPosition);}公众诠释getGroupCount(){ 返回group_list.size();}众长getGroupId(INT groupPosition){ 返回groupPosition;}公共查看getGroupView(INT groupPosition,布尔isExpanded, 查看convertView,父母的ViewGroup){ 字符串incoming_text =(字符串)getGroup(groupPosition); 如果(convertView == NULL){ LayoutInflater infalInflater =(LayoutInflater)上下文 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = infalInflater.inflate(R.layout.expandable_list_single_item, 空值); } TextView的项目=(TextView中)convertView.findViewById(R.id.expandable_list_single_item_text_view_group); item.setTypeface(NULL,Typeface.BOLD); item.setText(incoming_text); 返回convertView;}公共布尔hasStableIds(){ 返回true;}公共布尔isChildSelectable(INT groupPosition,诠释childPosition){ 返回true;}@覆盖公众诠释getChildTypeCount(){ 返回3;}@覆盖公众诠释getGroupType(INT groupPosition){ 返回super.getGroupType(groupPosition);}@覆盖公众诠释getGroupTypeCount(){ 返回3;}}
解决方案
我觉得你的主要错误在于公开查看getChildView(...)
:
如果(convertView == NULL)
实际上只达到了一次,当你加载你标记为第一种观点的一个的。那么,你是充气的第一个布局 R.layout.description_of_ads_expandable_list
和重用它在你的列表中的所有其他行。您正在检查子视图的负载类型的方式是危险的,因为它是不完整的。你觉得会happend如果 childPosition == 1安培;&安培; groupPosition == 0
? Booom! NullPointerException - 如果您的数据源具有第一组多了一个元素。所以,首先第一件事情;你要全面贯彻 HeterogeneousExpandableList接口的,如果你要使用不同的不同的布局您ExpandableListView组/儿童。
然后,使用上的布局应加载的条件接口的工作。
最后就重用视图问题上工作公开查看getChildView(...)
。
由于是这里的好人是一个片段,它可以帮助你(你根据张贴在适配器上):
公共类CommentsExpandableListAdapter扩展BaseExpandableListAdapter { // 4种儿童 私有静态最终诠释CHILD_TYPE_1 = 0; 私有静态最终诠释CHILD_TYPE_2 = 1; 私有静态最终诠释CHILD_TYPE_3 = 2; 私有静态最终诠释CHILD_TYPE_UNDEFINED = 3; // 3组类型 私有静态最终诠释GROUP_TYPE_1 = 0; 私有静态最终诠释GROUP_TYPE_2 = 1; 私有静态最终诠释GROUP_TYPE_3 = 2; 私人活动范围内; 私人地图<字符串列表<串GT;> comments_feed_collection; 私人列表<串GT; GROUP_LIST; 公共CommentsExpandableListAdapter(Activity上下文,列表<串GT; group_list中, 地图<字符串列表<串GT;> comments_feed_collection){ this.context =背景; this.comments_feed_collection = comments_feed_collection; this.group_list = GROUP_LIST; } 公共对象getChild(INT groupPosition,诠释childPosition){ 返回comments_feed_collection.get(group_list.get(groupPosition))获得(childPosition)。 } 众长getChildId(INT groupPosition,诠释childPosition){ 返回childPosition; } 公共查看getChildView(最终诠释groupPosition,最终诠释childPosition,布尔isLastChild,查看convertView,父母的ViewGroup){ 最后弦乐incoming_text =(字符串)getChild(groupPosition,childPosition); LayoutInflater吹气= context.getLayoutInflater(); INT childType = getChildType(groupPosition,childPosition); //我们需要建立一个新的电池容器 如果(convertView == NULL || convertView.getTag()!= childType){ 开关(childType){ 案例CHILD_TYPE_1: convertView = inflater.inflate(R.layout.description_of_ads_expandable_list,NULL); convertView.setTag(childType); 打破; 案例CHILD_TYPE_2: convertView = inflater.inflate(R.layout.comments_create_comment,NULL); convertView.setTag(childType); 打破; 案例CHILD_TYPE_3: convertView = inflater.inflate(R.layout.comments_expandable_list_child,NULL); convertView.setTag(childType); 打破; 案例CHILD_TYPE_UNDEFINED: convertView = inflater.inflate(R.layout.comments_undefined,NULL); convertView.setTag(childType); 打破; 默认: //也许我们应该实现一个默认行为,但它应该是好的,我们知道有4个孩子的类型吗? 打破; } } //我们将重用现有的 其他{ //没有什么在这里做我们真的只需要设置来看,我们在这两种情况下做内容 } 开关(childType){ 案例CHILD_TYPE_1: TextView的description_child =(TextView中)convertView.findViewById(R.id.description_of_ads_expandable_list_child_text_view); description_child.setText(incoming_text); 打破; 案例CHILD_TYPE_2: //定义如何呈现在CHILD_TYPE_2布局数据 打破; 案例CHILD_TYPE_3: //定义如何呈现在CHILD_TYPE_3布局数据 打破; 案例CHILD_TYPE_UNDEFINED: //定义如何呈现在CHILD_TYPE_UNDEFINED布局数据 打破; } 返回convertView; } 公众诠释getChildrenCount(INT groupPosition){ 串组名= group_list.get(groupPosition); 清单<串GT; groupContent = comments_feed_collection.get(组名); 返回groupContent.size(); } 公共对象getGroup(INT groupPosition){ 返回group_list.get(groupPosition); } 公众诠释getGroupCount(){ 返回group_list.size(); } 众长getGroupId(INT groupPosition){ 返回groupPosition; } 公共查看getGroupView(INT groupPosition,布尔isExpanded,查看convertView,父母的ViewGroup){ LayoutInflater吹气= context.getLayoutInflater(); 最后弦乐incoming_text =(字符串)getGroup(groupPosition); INT groupType = getGroupType(groupPosition); //我们需要建立一个新的电池容器 如果(convertView == NULL || convertView.getTag()!= groupType){ 开关(groupType){ 案例GROUP_TYPE_1: convertView = inflater.inflate(R.layout.expandable_list_single_item,NULL); 打破; 案例GROUP_TYPE_2: //现在用的是相同的布局事业上午镭石光电和不想创建其他的,但论文应该是不同的 //或组类型不应该存在 convertView = inflater.inflate(R.layout.expandable_list_single_item,NULL); 打破; 案例GROUP_TYPE_3: //现在用的是相同的布局事业上午镭石光电和不想创建其他的,但论文应该是不同的 //或组类型不应该存在 convertView = inflater.inflate(R.layout.expandable_list_single_item,NULL); 打破; 默认: //也许我们应该实现一个默认的行为,但它应该是确定我们知道有3组类型吧? 打破; } } //我们将重用现有的 其他{ //没有什么在这里做我们真的只需要设置来看,我们在这两种情况下做内容 } 开关(groupType){ 案例GROUP_TYPE_1: TextView的项目=(TextView中)convertView.findViewById(R.id.expandable_list_single_item_text_view_group); item.setTypeface(NULL,Typeface.BOLD); item.setText(incoming_text); 打破; 案例GROUP_TYPE_2: // TODO:定义如何呈现在GROUPE_TYPE_2布局数据 //由于我使用的布局相同GROUPE_TYPE_1我可以做同样的事情上面一样,但我选择什么都不做 打破; 案例GROUP_TYPE_3: // TODO:定义如何呈现在GROUPE_TYPE_3布局数据 //由于我使用的布局相同GROUPE_TYPE_1我可以做同样的事情上面一样,但我选择什么都不做 打破; 默认: //也许我们应该实现一个默认的行为,但它应该是确定我们知道有3组类型吧? 打破; } 返回convertView; } 公共布尔hasStableIds(){ 返回true; } 公共布尔isChildSelectable(INT groupPosition,诠释childPosition){ 返回false; } @覆盖 公众诠释getChildTypeCount(){ 返回4; //我定义了4个孩子的类型(CHILD_TYPE_1,CHILD_TYPE_2,CHILD_TYPE_3,CHILD_TYPE_UNDEFINED) } @覆盖 公众诠释getGroupTypeCount(){ 返回3; //我定义了3种组(GROUP_TYPE_1,GROUP_TYPE_2,GROUP_TYPE_3) } @覆盖 公众诠释getGroupType(INT groupPosition){ 开关(groupPosition){ 情况下0: 返回GROUP_TYPE_1; 情况1: 返回GROUP_TYPE_1; 案例2: 返回GROUP_TYPE_2; 默认: 返回GROUP_TYPE_3; } } @覆盖 公众诠释getChildType(INT groupPosition,诠释childPosition){ 开关(groupPosition){ 情况下0: 开关(childPosition){ 情况下0: 返回CHILD_TYPE_1; 情况1: 返回CHILD_TYPE_UNDEFINED; 案例2: 返回CHILD_TYPE_UNDEFINED; } 打破; 情况1: 开关(childPosition){ 情况下0: 返回CHILD_TYPE_2; 情况1: 返回CHILD_TYPE_3; 案例2: 返回CHILD_TYPE_3; } 打破; 默认: 返回CHILD_TYPE_UNDEFINED; } 返回CHILD_TYPE_UNDEFINED; }}
这是它的样子:
希望这会有所帮助,让我知道,如果它确实/犯规。
I've been having issues trying to do this. I can't seem to get it right, I want to control each parent + children of that parent. ExpandableListView has been giving me a headache. package comments;
public class CommentsExpandableListAdapter extends BaseExpandableListAdapter {
private Activity context;
private Map<String, List<String>> comments_feed_collection;
private List<String> group_list;
private boolean a_comment = false;
public CommentsExpandableListAdapter(Activity context, List<String> group_list,
Map<String, List<String>> comments_feed_collection) {
this.context = context;
this.comments_feed_collection = comments_feed_collection;
this.group_list = group_list;
}
public Object getChild(int groupPosition, int childPosition) {
return comments_feed_collection.get(group_list.get(groupPosition)).get(childPosition);
}
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
public View getChildView(final int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final String incoming_text = (String) getChild(groupPosition, childPosition);
LayoutInflater inflater = context.getLayoutInflater();
if (convertView == null) {
//first view
if(childPosition==0 && groupPosition==0) {
convertView = inflater.inflate(R.layout.description_of_ads_expandable_list, null);
TextView description_child = (TextView) convertView.findViewById(R.id.description_of_ads_expandable_list_child_text_view);
description_child.setText(incoming_text);
}else if(childPosition==0 && groupPosition==1){
//second view view
convertView = inflater.inflate(R.layout.comments_create_comment, null);
}else if(childPosition>=1 && groupPosition>=1){
//thrid view
convertView = inflater.inflate(R.layout.comments_expandable_list_child, null);
}
}
return convertView;
}
public int getChildrenCount(int groupPosition) {
return comments_feed_collection.get(group_list.get(groupPosition)).size();
}
public Object getGroup(int groupPosition) {
return group_list.get(groupPosition);
}
public int getGroupCount() {
return group_list.size();
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String incoming_text = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.expandable_list_single_item,
null);
}
TextView item = (TextView) convertView.findViewById(R.id.expandable_list_single_item_text_view_group);
item.setTypeface(null, Typeface.BOLD);
item.setText(incoming_text);
return convertView;
}
public boolean hasStableIds() {
return true;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
@Override
public int getChildTypeCount() {
return 3;
}
@Override
public int getGroupType(int groupPosition) {
return super.getGroupType(groupPosition);
}
@Override
public int getGroupTypeCount() {
return 3;
}
}
解决方案
I think your main mistake resides in public View getChildView(...)
:
if (convertView == null)
is actually only reached once and that's when you load the one you marked as first view. So you are inflating the first layout R.layout.description_of_ads_expandable_list
and reusing it for all the other lines in your list.
The way you are checking for the type of child view to load is dangerous because it's incomplete . What do you think will happend if childPosition==1 && groupPosition==0
? Booom! NullPointerException if your data source has one more element for the first group.
So first things first; you should fully implement HeterogeneousExpandableList interface if you want to use different layouts for different groups/children of your ExpandableListView.
Then using that interface work on the conditions of which layout should be loaded.
Finally work on the reuse view issue on public View getChildView(...)
.
Since am a nice guy here is a a snippet that should help you (based on the adapter you post) :
public class CommentsExpandableListAdapter extends BaseExpandableListAdapter {
// 4 Child types
private static final int CHILD_TYPE_1 = 0;
private static final int CHILD_TYPE_2 = 1;
private static final int CHILD_TYPE_3 = 2;
private static final int CHILD_TYPE_UNDEFINED = 3;
// 3 Group types
private static final int GROUP_TYPE_1 = 0;
private static final int GROUP_TYPE_2 = 1;
private static final int GROUP_TYPE_3 = 2;
private Activity context;
private Map<String, List<String>> comments_feed_collection;
private List<String> group_list;
public CommentsExpandableListAdapter(Activity context, List<String> group_list,
Map<String, List<String>> comments_feed_collection) {
this.context = context;
this.comments_feed_collection = comments_feed_collection;
this.group_list = group_list;
}
public Object getChild(int groupPosition, int childPosition) {
return comments_feed_collection.get(group_list.get(groupPosition)).get(childPosition);
}
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final String incoming_text = (String) getChild(groupPosition, childPosition);
LayoutInflater inflater = context.getLayoutInflater();
int childType = getChildType(groupPosition, childPosition);
// We need to create a new "cell container"
if (convertView == null || convertView.getTag() != childType) {
switch (childType) {
case CHILD_TYPE_1:
convertView = inflater.inflate(R.layout.description_of_ads_expandable_list, null);
convertView.setTag(childType);
break;
case CHILD_TYPE_2:
convertView = inflater.inflate(R.layout.comments_create_comment, null);
convertView.setTag(childType);
break;
case CHILD_TYPE_3:
convertView = inflater.inflate(R.layout.comments_expandable_list_child, null);
convertView.setTag(childType);
break;
case CHILD_TYPE_UNDEFINED:
convertView = inflater.inflate(R.layout.comments_undefined, null);
convertView.setTag(childType);
break;
default:
// Maybe we should implement a default behaviour but it should be ok we know there are 4 child types right?
break;
}
}
// We'll reuse the existing one
else {
// There is nothing to do here really we just need to set the content of view which we do in both cases
}
switch (childType) {
case CHILD_TYPE_1:
TextView description_child = (TextView) convertView.findViewById(R.id.description_of_ads_expandable_list_child_text_view);
description_child.setText(incoming_text);
break;
case CHILD_TYPE_2:
//Define how to render the data on the CHILD_TYPE_2 layout
break;
case CHILD_TYPE_3:
//Define how to render the data on the CHILD_TYPE_3 layout
break;
case CHILD_TYPE_UNDEFINED:
//Define how to render the data on the CHILD_TYPE_UNDEFINED layout
break;
}
return convertView;
}
public int getChildrenCount(int groupPosition) {
String groupName = group_list.get(groupPosition);
List<String> groupContent = comments_feed_collection.get(groupName);
return groupContent.size();
}
public Object getGroup(int groupPosition) {
return group_list.get(groupPosition);
}
public int getGroupCount() {
return group_list.size();
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
final String incoming_text = (String) getGroup(groupPosition);
int groupType = getGroupType(groupPosition);
// We need to create a new "cell container"
if (convertView == null || convertView.getTag() != groupType) {
switch (groupType) {
case GROUP_TYPE_1 :
convertView = inflater.inflate(R.layout.expandable_list_single_item, null);
break;
case GROUP_TYPE_2:
// Am using the same layout cause am lasy and don't wanna create other ones but theses should be different
// or the group type shouldnt exist
convertView = inflater.inflate(R.layout.expandable_list_single_item, null);
break;
case GROUP_TYPE_3:
// Am using the same layout cause am lasy and don't wanna create other ones but theses should be different
// or the group type shouldnt exist
convertView = inflater.inflate(R.layout.expandable_list_single_item, null);
break;
default:
// Maybe we should implement a default behaviour but it should be ok we know there are 3 group types right?
break;
}
}
// We'll reuse the existing one
else {
// There is nothing to do here really we just need to set the content of view which we do in both cases
}
switch (groupType) {
case GROUP_TYPE_1 :
TextView item = (TextView) convertView.findViewById(R.id.expandable_list_single_item_text_view_group);
item.setTypeface(null, Typeface.BOLD);
item.setText(incoming_text);
break;
case GROUP_TYPE_2:
//TODO: Define how to render the data on the GROUPE_TYPE_2 layout
// Since i use the same layout as GROUPE_TYPE_1 i could do the same thing as above but i choose to do nothing
break;
case GROUP_TYPE_3:
//TODO: Define how to render the data on the GROUPE_TYPE_3 layout
// Since i use the same layout as GROUPE_TYPE_1 i could do the same thing as above but i choose to do nothing
break;
default:
// Maybe we should implement a default behaviour but it should be ok we know there are 3 group types right?
break;
}
return convertView;
}
public boolean hasStableIds() {
return true;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
@Override
public int getChildTypeCount() {
return 4; // I defined 4 child types (CHILD_TYPE_1, CHILD_TYPE_2, CHILD_TYPE_3, CHILD_TYPE_UNDEFINED)
}
@Override
public int getGroupTypeCount() {
return 3; // I defined 3 groups types (GROUP_TYPE_1, GROUP_TYPE_2, GROUP_TYPE_3)
}
@Override
public int getGroupType(int groupPosition) {
switch (groupPosition) {
case 0:
return GROUP_TYPE_1;
case 1:
return GROUP_TYPE_1;
case 2:
return GROUP_TYPE_2;
default:
return GROUP_TYPE_3;
}
}
@Override
public int getChildType(int groupPosition, int childPosition) {
switch (groupPosition) {
case 0:
switch (childPosition) {
case 0:
return CHILD_TYPE_1;
case 1:
return CHILD_TYPE_UNDEFINED;
case 2:
return CHILD_TYPE_UNDEFINED;
}
break;
case 1:
switch (childPosition) {
case 0:
return CHILD_TYPE_2;
case 1:
return CHILD_TYPE_3;
case 2:
return CHILD_TYPE_3;
}
break;
default:
return CHILD_TYPE_UNDEFINED;
}
return CHILD_TYPE_UNDEFINED;
}
}
And this is how it looks like :
Hope this helps, let me know if it does/doesnt.