如何将Viewholder与ExpandableListView一起使用?

时间:2016-08-09 16:10:10

标签: android android-studio expandablelistview android-viewholder

我正在尝试在我的应用中创建ExpandableListView。它有两组:第一组是颜色,第二组是符号。点击的第一组工作正常。但是,第二组显示第一组中的行(如果第二组中有更多项,那么'额外'将是正确的。)

例如,假设“颜色”为白色,黑色,红色和蓝色,符号为“/”和“。”。

如果我启动活动并单击颜色,则它们会正确显示。如果我点击“符号”,我会看到白色和黑色。

如果我先点击'符号',那么我会看到'/'和'。',但是当我点击颜色时,我会看到'/','。',红色,蓝色。

我在线搜索并确定我需要使用ViewHolders以避免在我更改组时重复使用相同的视图。我虽然无法实现它。起初它没有任何区别,当我点击第二组时,当前版本崩溃了。我认为问题的一部分是每个组都有不同的子布局(即符号与颜色不同)。

目前这就是我所拥有的(我已经展示了我认为的相关内容;如果我遗漏了任何重要内容,我可以添加它):

public class ColourSymbolKeyAdapter extends BaseExpandableListAdapter {

    private Context context;
    private HashMap<String, List<KeyItem>> childDataSource;
    private List<String> parentDataSource;

    public ColourSymbolKeyAdapter(Context context,
                                  List<String> childParent,
                                  HashMap<String, List<KeyItem>> child) {

        this.context = context;
        this.parentDataSource = childParent;
        this.childDataSource = child;
    }

... Left out various override functions ...

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

        View v = convertView;
        GroupViewHolder holder;

        if(v == null) {
            LayoutInflater inflater =
                    (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.expandablelist_parent, parent, false);
            holder = new GroupViewHolder();

            holder.mGroupName = (TextView) v.findViewById(R.id.textViewParent);
            v.setTag(holder);
        }else {
            holder = (GroupViewHolder) v.getTag();
        }

        String parentHeader = (String) getGroup(groupPosition);
        holder.mGroupName.setText(parentHeader);
        return v;
    }

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

        View row = convertView;
        KeyItem childItem = (KeyItem) getChild(groupPosition, childPosition);
        ColourViewHolder colourviewholder;
        SymbolViewHolder symbolviewholder;

        LayoutInflater inflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if(childItem.getPatternColour() == null) { // This is a symbol row

            if(row == null) {
                symbolviewholder = new SymbolViewHolder();
                row = inflater.inflate(R.layout.expandablelist_child_symbol, parent, false);
                symbolviewholder.mChildName = (TextView) row.findViewById(R.id.symbol_desc);
                symbolviewholder.mSymbolCell = (SymbolCell) row.findViewById(R.id.symbol_cell);
                row.setTag(symbolviewholder);
            }else {
                symbolviewholder = (SymbolViewHolder) row.getTag();
            }

            String drawableName = childItem.getPatternSymbol().getDrawable();
            final int resourceId = context.getResources().getIdentifier(drawableName, "drawable", context.getPackageName());
            Drawable drawable;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                drawable = context.getResources().getDrawable(resourceId, context.getTheme());
            } else {
                drawable = context.getResources().getDrawable(resourceId);
            }

            symbolviewholder.mSymbolCell.setDrawable(drawable);
            symbolviewholder.mChildName.setText(childItem.getPatternSymbol().getSymbolDescription());

        }else { // This is a colour row
            if(row == null) {
                colourviewholder = new ColourViewHolder();
                row = inflater.inflate(R.layout.expandablelist_child_colour, parent, false);
                colourviewholder.mChildName = (TextView) row.findViewById(R.id.colour_name);
                colourviewholder.mChildDesc = (TextView) row.findViewById(R.id.colour_desc);
                colourviewholder.mColourCell = (ColourCell) row.findViewById(R.id.colour_cell);
                row.setTag(colourviewholder);
            }else {
                colourviewholder = (ColourViewHolder) row.getTag();
            }

            colourviewholder.mColourCell.setColour(childItem.getPatternColour());
            colourviewholder.mChildName.setText(childItem.getPatternColour().getName());
            colourviewholder.mChildDesc.setText(childItem.getPatternColour().getDescription());
        }

        return row;
    }

    public final class GroupViewHolder {

        TextView mGroupName;
    }

    public final class ColourViewHolder {

        ColourCell mColourCell;
        TextView mChildName, mChildDesc;
    }

    public final class SymbolViewHolder {

        SymbolCell mSymbolCell;
        TextView mChildName;
    }
}

父级布局(expandablelist_parent.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="match_parent"
    android:id="@+id/parentView">

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/textViewParent"
        android:textColor="#000000"
        android:textAppearance="@style/ParagraphBold">
    </TextView>

</LinearLayout>

颜色行的布局(expandablelist_child_colour.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="match_parent"
    android:padding="@dimen/small_padding"
    android:id="@+id/childViewColour"
    android:orientation="horizontal">

    <com.myname.appname.ColourCell xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="@dimen/grid_cell_column_width"
        android:layout_height="@dimen/grid_cell_column_width"
        android:id="@+id/colour_cell"
        android:layout_marginRight="@dimen/small_padding" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="@style/ParagraphBold"
            android:textColor="@color/colorPrimaryDark"
            android:id="@+id/colour_name">
        </TextView>

        <TextView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="@style/Paragraph"
            android:textColor="@color/colorPrimaryDark"
            android:id="@+id/colour_desc">
        </TextView>

    </LinearLayout>

</LinearLayout>

和符号行(expandablelist_child_symbol.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="match_parent"
    android:id="@+id/childViewSymbol"
    android:padding="@dimen/small_padding">

    <com.myname.appname.SymbolCell xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="@dimen/grid_cell_column_width"
        android:layout_height="@dimen/grid_cell_column_width"
        android:textAppearance="@style/Paragraph"
        android:id="@+id/symbol_cell"
        android:layout_marginRight="@dimen/small_padding" />

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textColor="@color/colorPrimaryDark"
        android:id="@+id/symbol_desc">
    </TextView>

</LinearLayout>

如果我先点击'颜色'组,然后点击'符号'组,它就会崩溃:symbolviewholder = (SymbolViewHolder) row.getTag()

4 个答案:

答案 0 :(得分:2)

由于您有2个不同的子布局,因此需要覆盖getChildTypeCount()getChildType(),以便适配器将接收正确的视图类型以供重用。否则,在某些情况下,在尝试检索ViewHolder时会出现 ClassCastException

@Override
public int getChildTypeCount() {
    return 2;
}

@Override
public int getChildType(int groupPosition, int childPosition) {
    KeyItem childItem = (KeyItem) getChild(groupPosition, childPosition);
    return (childItem.getPatternColour() == null) ? 0 : 1;
}

有关详细信息,请参阅HeterogeneousExpandableList文档。

答案 1 :(得分:1)

我认为使用Expendable Recyclerview使用自定义viewholder解决您的问题会更好。有关详细信息,请参阅链接。 https://guides.codepath.com/android/Heterogenous-Layouts-inside-RecyclerView

答案 2 :(得分:1)

您可以使用此library轻松实现此功能,有一个完整示例here

基本上,您将项目分组为:

class MySection extends StatelessSection {

    String header;
    List<String> list;
    boolean expanded = true;

    public MySection(String header, List<String> list) {
        // call constructor with layout resources for this Section header and items 
        super(R.layout.section_header, R.layout.section_item);
        this.myHeader = header;
        this.myList = list;
    }

    @Override
    public int getContentItemsTotal() {
        return expanded? list.size() : 0;
    }

    @Override
    public RecyclerView.ViewHolder getHeaderViewHolder(View view) {
        return new HeaderViewHolder(view);
    }

    @Override
    public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) {
        final HeaderViewHolder headerHolder = (HeaderViewHolder) holder;

        headerHolder.tvTitle.setText(title);

        headerHolder.rootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                expanded = !expanded;
                headerHolder.imgArrow.setImageResource(
                        expanded ? R.drawable.ic_keyboard_arrow_up_black_18dp : R.drawable.ic_keyboard_arrow_down_black_18dp
                );
                sectionAdapter.notifyDataSetChanged();
            }
        });
    }

    @Override
    public RecyclerView.ViewHolder getItemViewHolder(View view) {
        // return a custom instance of ViewHolder for the items of this section
        return new MyItemViewHolder(view);
    }

    @Override
    public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
        MyItemViewHolder itemHolder = (MyItemViewHolder) holder;

        // bind your view here
        itemHolder.tvItem.setText(list.get(position));
    }
}

然后创建部分的实例并设置适配器:

// Create an instance of SectionedRecyclerViewAdapter 
SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();

// Add your Sections
sectionAdapter.addSection(new MySection("Colours", Arrays.asList(new String[] {"white", "red", "black", "blue" })));
sectionAdapter.addSection(new MySection("Symbols", Arrays.asList(new String[] {"/", "." })));

// Set up your RecyclerView with the SectionedRecyclerViewAdapter
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(sectionAdapter);

答案 3 :(得分:1)

试试这个library。您可以用它重新ExpandableListView