不同组的不同子布局ExpandableListView

时间:2015-04-23 14:25:26

标签: java android expandablelistview

我在尝试这样做时遇到了问题。我似乎无法做到正确,我想控制那个父母的每个父母+孩子。 ExpandableListView让我很头疼。 包评论;

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;
}
}

1 个答案:

答案 0 :(得分:24)

我认为你的主要错误在于public View getChildView(...)

  • 条件if (convertView == null)实际上只到达一次,当您加载标记为第一个视图的条件时。因此,您要对第一个布局R.layout.description_of_ads_expandable_list进行充气,并将其重新用于列表中的所有其他行。
  • 检查要加载的子视图类型的方式很危险,因为它不完整。如果childPosition==1 && groupPosition==0,您认为会发生什么? Booom! NullPointerException如果您的数据源还有一个元素用于第一组。

首先是第一件事;如果要对ExpandableListView的不同组/子项使用不同的布局,则应完全实现HeterogeneousExpandableList interface

然后使用该接口处理应加载布局的条件。

最后处理public View getChildView(...)上的重用视图问题。

既然我是一个好人,这里有一个应该帮助你的片段(基于你发布的适配器):

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;
    }
}

这就是它的样子:

CommentsExpandableListAdapter implementation result

希望这会有所帮助,让我知道它是否确实存在。