RecyclerView - 元素数量未知的列表项
RecyclerView - listitem with unknown amount of elements
我遇到了以下情况:我有一个具有 3 种不同视图类型的 RecyclerView。每个都包含一个副标题,然后是一个单选按钮组、复选框或一个 editText。问题是:元素(编辑文本、复选框、单选按钮)的数量是可变的,所以我无法创建静态模板作为视图类型。所以我试图达到这样的效果(例如带有单选按钮):
LISTVIEW
------------------
row1
1) choice1
2) choice2
------------------
row2
1) choice1
2) choice2
3) choice3
------------------
row3
1) choice1
-------------------
有什么好的方法吗?感谢您的时间和帮助! :)
编辑:ChaitanyaAtkuris 的回答很有帮助,但我在 onBindViewHolder() 中遇到了 ClassCastException。它说 "cant cast TitleHolder to InputHolder" ... 但我无法弄清楚为什么持有人 object 实际上是一个 TitleHolder,因为它使用了正确的大小写 (INPUT)。这是我的适配器代码
public class RecAdapter extends RecyclerView.Adapter {
private List<Object> items;
private final int TITLE_VIEW = 0;
private final int RADIO_GROUP = 1;
private final int CHECK_BOX = 2;
private final int INPUT = 3;
public RecAdapter(List<Object> data) {
this.items = data;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case CHECK_BOX:
View v1 = inflater.inflate(R.layout.child_checkbox, parent, false);
viewHolder = new CheckboxHolder(v1);
break;
case TITLE_VIEW:
View v2 = inflater.inflate(R.layout.child_title, parent, false);
viewHolder = new TitleHolder(v2);
break;
case INPUT:
View v3 = inflater.inflate(R.layout.child_inputfield, parent, false);
viewHolder = new TitleHolder(v3);
break;
}
return viewHolder;
}
@Override
public int getItemViewType(int position) {
ListItem item = (ListItem) items.get(position);
if (item.getviewType()==TITLE_VIEW) {
return TITLE_VIEW;
} else if (item.getviewType()==RADIO_GROUP) {
return RADIO_GROUP;
} else if (item.getviewType()==CHECK_BOX) {
return CHECK_BOX;
} else if (item.getviewType()==INPUT) {
return INPUT;
}
return -1;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case CHECK_BOX:
CheckboxHolder checkboxHolder = (CheckboxHolder) holder;
configureCheckBoxHolder(checkboxHolder, position);
break;
case TITLE_VIEW:
TitleHolder titleHolder = (TitleHolder) holder;
configureTitleHolder(titleHolder, position);
break;
case INPUT:
InputHolder inputHolder = (InputHolder) holder;
configureInputHolder(inputHolder, position);
break;
}
}
private void configureCheckBoxHolder(CheckboxHolder holder,int position) {
CheckBoxElement boxElement = (CheckBoxElement) items.get(position);
if (boxElement != null) {
holder.box.setText(boxElement.getText());
}
}
private void configureInputHolder(InputHolder holder,int position) {
InputField field = (InputField) items.get(position);
if (field != null) {
holder.title.setText(field.getSubtitle());
}
}
private void configureTitleHolder(TitleHolder holder,int position) {
TitlePojo titlePojo = (TitlePojo) items.get(position);
if (titlePojo != null) {
holder.titleText.setText(titlePojo.getTitle());
}
}
@Override
public int getItemCount() {
return items.size();
}
private class InputHolder extends RecyclerView.ViewHolder {
private TextView title;
private EditText inputfield;
public InputHolder(View v1) {
super(v1);
title = (TextView) v1.findViewById(R.id.inputTitleItem);
inputfield = (EditText) v1.findViewById(R.id.fieldItem);
}
}
private class TitleHolder extends RecyclerView.ViewHolder {
private TextView titleText;
public TitleHolder(View v1) {
super(v1);
titleText = (TextView) v1.findViewById(R.id.titleView);
}
}
private class CheckboxHolder extends RecyclerView.ViewHolder {
private CheckBox box;
public CheckboxHolder(View v1) {
super(v1);
box = (CheckBox) v1.findViewById(R.id.checkboxItem);
}
}
private class RadioGroupHolder extends RecyclerView.ViewHolder {
private RadioGroup group;
public RadioGroupHolder(View v1) {
super(v1);
}
}
}
@Pynnie,这没什么大不了的。我相信你会解决的。让我给你一些解决这个问题的方法。
第 1 步:正如我们提到的三种不同类型的视图,让我们看一下 List<Object> dataList= new ArrayList();
此列表将决定要显示的总视图。
第 2 步:现在,让我们为每个可用组件创建一个 viewType。例如
private final int TEXT_VIEW = 0; //For TextView
private final int RADIO_GROUP = 1; //For RadioGroup
private final int CHECK_BOX = 2; //For individual Checkbox
private final int EDIT_TEXT = 3; //For Edit text individual
现在在根据结构动态存储数据的同时,按如下方式存储。
public class TextViewPojo { // This will used for identifying textViews
public String text;
//Any other necessary variables to hold data to display
}
public class EditTextPojo { // This will used for identifying editText
public String text;
//Any other necessary variables to hold data to display
}
public class RadioGroupPojo { // This will used for identifying RadioGroup
public int noOfRadioButtons;
//Any other necessary variables to hold data to display
}
public class CheckBoxPojo { // This will used for identifying checkbox
public String text;
//Any other necessary variables to hold data to display
}
// ------------------
row1 - 表示副标题的 TextView -> dataList.add(new TextViewPojo());
1) 选择 1 - EditText -> dataList.add(new EditTextPojo());
2) choice2- EditText -> dataList.add(new EditTextPojo());
//--------------------
row2- 表示副标题的 TextView -> dataList.add(new TextViewPojo());
1) choice1 -CheckBox -> dataList.add(new CheckBoxPojo());
2) choice2-CheckBox -> dataList.add(new CheckBoxPojo());
3) choice3-CheckBox -> dataList.add(new CheckBoxPojo());
//--------------------
row3 - 表示副标题的 TextView -> dataList.add(new TextViewPojo());
1) choice1 - RadioGroup 对于 choice1 和 choice2 都认为是一组单选按钮,-> RadioGroup -> dataList.add(new RadioGroupPojo());
2)选择2
//--------------------
现在介绍 RecyclerView 适配器实现
public class RecyclerViewsAdapter 扩展 RecyclerView.Adapter {
// The items to display in your RecyclerView
private List<Object> items;
private final int TEXT_VIEW = 0; //For TextView
private final int RADIO_GROUP = 1; //For RadioGroup
private final int CHECK_BOX = 2; //For individual Checkbox
private final int EDIT_TEXT = 3; //For Edit text individual
public RecyclerViewsAdapter(List<Object> data,) {
this.items = data;
}
现在要区分数据,我们将使用 getViewType() 方法
//Returns 用于视图回收的位置项的视图类型。
@Override
public int getItemViewType(int position) {
if (items.get(position) instanceof CheckBoxPojo) {
return CHECK_BOX;
} else if (items.get(position) instanceof RadioGroupPojo) {
return RADIOGROUP;
} //All the conditions follow..
return -1;
}
现在为每种类型创建视图持有者。
public class ViewHolder1 extends RecyclerView.ViewHolder {
private TextView label1;
public ViewHolder1(View v) {
super(v);
label1 = (TextView) v.findViewById(R.id.text1);
}
public TextView getLabel1() {
return label1;
}
public void setLabel1(TextView label1) {
this.label1 = label1;
}
}
//相应的所有其他 viewHolders。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (viewType) {
case CHECKBOX:
View v1 = inflater.inflate(R.layout.layout_viewholder1, viewGroup, false);
viewHolder = new ViewHolder1(v1);
break;
case RADIOGROUP:
View v2 = inflater.inflate(R.layout.layout_viewholder2, viewGroup, false);
viewHolder = new ViewHolder2(v2);
break;
//其余情况如下。
NExt 将数据设置为视图
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case CHECKBOX:
ViewHolder1 vh1 = (ViewHolder1) viewHolder;
configureViewHolder1(vh1, position);
break;
case RADIOGROUp:
ViewHolder2 vh2 = (ViewHolder2) viewHolder;
configureViewHolder2(vh2, position);
break;
//Rest cases follow.
default:
RecyclerViewSimpleTextViewHolder vh = (RecyclerViewSimpleTextViewHolder) viewHolder;
configureDefaultViewHolder(vh, position);
break;
}
}
private void configureViewHolder1(ViewHolder1 vh1, int position) {
CheckBoxPojo user = (CheckBoxPojo) items.get(position);
if (user != null) {
vh1.getCheckBox1().setChecked(user.isChecked);
}
}
private void configureViewHolder2(ViewHolder2 vh2) {
//vh2.getImageView().setImageResource(R.drawable.sample_golden_gate);
Similarly rest follows.
}
大功告成!!!您可以以任何方式配置,可能有多少,它们可能有多随机。
参考:https://guides.codepath.com/android/Heterogenous-Layouts-inside-RecyclerView
编辑:
找出您添加的代码段中的问题。以下是问题:
case TITLE_VIEW: View v2 = inflater.inflate(R.layout.child_title, parent, false); viewHolder = new TitleHolder(v2); break; case INPUT: View v3 = inflater.inflate(R.layout.child_inputfield, parent, false); viewHolder = new TitleHolder(v3); break;
在这两种情况下,您都只使用标题持有人。
我遇到了以下情况:我有一个具有 3 种不同视图类型的 RecyclerView。每个都包含一个副标题,然后是一个单选按钮组、复选框或一个 editText。问题是:元素(编辑文本、复选框、单选按钮)的数量是可变的,所以我无法创建静态模板作为视图类型。所以我试图达到这样的效果(例如带有单选按钮):
LISTVIEW
------------------
row1
1) choice1
2) choice2
------------------
row2
1) choice1
2) choice2
3) choice3
------------------
row3
1) choice1
-------------------
有什么好的方法吗?感谢您的时间和帮助! :)
编辑:ChaitanyaAtkuris 的回答很有帮助,但我在 onBindViewHolder() 中遇到了 ClassCastException。它说 "cant cast TitleHolder to InputHolder" ... 但我无法弄清楚为什么持有人 object 实际上是一个 TitleHolder,因为它使用了正确的大小写 (INPUT)。这是我的适配器代码
public class RecAdapter extends RecyclerView.Adapter {
private List<Object> items;
private final int TITLE_VIEW = 0;
private final int RADIO_GROUP = 1;
private final int CHECK_BOX = 2;
private final int INPUT = 3;
public RecAdapter(List<Object> data) {
this.items = data;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case CHECK_BOX:
View v1 = inflater.inflate(R.layout.child_checkbox, parent, false);
viewHolder = new CheckboxHolder(v1);
break;
case TITLE_VIEW:
View v2 = inflater.inflate(R.layout.child_title, parent, false);
viewHolder = new TitleHolder(v2);
break;
case INPUT:
View v3 = inflater.inflate(R.layout.child_inputfield, parent, false);
viewHolder = new TitleHolder(v3);
break;
}
return viewHolder;
}
@Override
public int getItemViewType(int position) {
ListItem item = (ListItem) items.get(position);
if (item.getviewType()==TITLE_VIEW) {
return TITLE_VIEW;
} else if (item.getviewType()==RADIO_GROUP) {
return RADIO_GROUP;
} else if (item.getviewType()==CHECK_BOX) {
return CHECK_BOX;
} else if (item.getviewType()==INPUT) {
return INPUT;
}
return -1;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case CHECK_BOX:
CheckboxHolder checkboxHolder = (CheckboxHolder) holder;
configureCheckBoxHolder(checkboxHolder, position);
break;
case TITLE_VIEW:
TitleHolder titleHolder = (TitleHolder) holder;
configureTitleHolder(titleHolder, position);
break;
case INPUT:
InputHolder inputHolder = (InputHolder) holder;
configureInputHolder(inputHolder, position);
break;
}
}
private void configureCheckBoxHolder(CheckboxHolder holder,int position) {
CheckBoxElement boxElement = (CheckBoxElement) items.get(position);
if (boxElement != null) {
holder.box.setText(boxElement.getText());
}
}
private void configureInputHolder(InputHolder holder,int position) {
InputField field = (InputField) items.get(position);
if (field != null) {
holder.title.setText(field.getSubtitle());
}
}
private void configureTitleHolder(TitleHolder holder,int position) {
TitlePojo titlePojo = (TitlePojo) items.get(position);
if (titlePojo != null) {
holder.titleText.setText(titlePojo.getTitle());
}
}
@Override
public int getItemCount() {
return items.size();
}
private class InputHolder extends RecyclerView.ViewHolder {
private TextView title;
private EditText inputfield;
public InputHolder(View v1) {
super(v1);
title = (TextView) v1.findViewById(R.id.inputTitleItem);
inputfield = (EditText) v1.findViewById(R.id.fieldItem);
}
}
private class TitleHolder extends RecyclerView.ViewHolder {
private TextView titleText;
public TitleHolder(View v1) {
super(v1);
titleText = (TextView) v1.findViewById(R.id.titleView);
}
}
private class CheckboxHolder extends RecyclerView.ViewHolder {
private CheckBox box;
public CheckboxHolder(View v1) {
super(v1);
box = (CheckBox) v1.findViewById(R.id.checkboxItem);
}
}
private class RadioGroupHolder extends RecyclerView.ViewHolder {
private RadioGroup group;
public RadioGroupHolder(View v1) {
super(v1);
}
}
}
@Pynnie,这没什么大不了的。我相信你会解决的。让我给你一些解决这个问题的方法。
第 1 步:正如我们提到的三种不同类型的视图,让我们看一下 List<Object> dataList= new ArrayList();
此列表将决定要显示的总视图。
第 2 步:现在,让我们为每个可用组件创建一个 viewType。例如
private final int TEXT_VIEW = 0; //For TextView
private final int RADIO_GROUP = 1; //For RadioGroup
private final int CHECK_BOX = 2; //For individual Checkbox
private final int EDIT_TEXT = 3; //For Edit text individual
现在在根据结构动态存储数据的同时,按如下方式存储。
public class TextViewPojo { // This will used for identifying textViews
public String text;
//Any other necessary variables to hold data to display
}
public class EditTextPojo { // This will used for identifying editText
public String text;
//Any other necessary variables to hold data to display
}
public class RadioGroupPojo { // This will used for identifying RadioGroup
public int noOfRadioButtons;
//Any other necessary variables to hold data to display
}
public class CheckBoxPojo { // This will used for identifying checkbox
public String text;
//Any other necessary variables to hold data to display
}
// ------------------
row1 - 表示副标题的 TextView -> dataList.add(new TextViewPojo());
1) 选择 1 - EditText -> dataList.add(new EditTextPojo());
2) choice2- EditText -> dataList.add(new EditTextPojo());
//--------------------
row2- 表示副标题的 TextView -> dataList.add(new TextViewPojo());
1) choice1 -CheckBox -> dataList.add(new CheckBoxPojo());
2) choice2-CheckBox -> dataList.add(new CheckBoxPojo());
3) choice3-CheckBox -> dataList.add(new CheckBoxPojo());
//--------------------
row3 - 表示副标题的 TextView -> dataList.add(new TextViewPojo());
1) choice1 - RadioGroup 对于 choice1 和 choice2 都认为是一组单选按钮,-> RadioGroup -> dataList.add(new RadioGroupPojo());
2)选择2
//--------------------
现在介绍 RecyclerView 适配器实现
public class RecyclerViewsAdapter 扩展 RecyclerView.Adapter {
// The items to display in your RecyclerView
private List<Object> items;
private final int TEXT_VIEW = 0; //For TextView
private final int RADIO_GROUP = 1; //For RadioGroup
private final int CHECK_BOX = 2; //For individual Checkbox
private final int EDIT_TEXT = 3; //For Edit text individual
public RecyclerViewsAdapter(List<Object> data,) {
this.items = data;
}
现在要区分数据,我们将使用 getViewType() 方法
//Returns 用于视图回收的位置项的视图类型。
@Override
public int getItemViewType(int position) {
if (items.get(position) instanceof CheckBoxPojo) {
return CHECK_BOX;
} else if (items.get(position) instanceof RadioGroupPojo) {
return RADIOGROUP;
} //All the conditions follow..
return -1;
}
现在为每种类型创建视图持有者。
public class ViewHolder1 extends RecyclerView.ViewHolder {
private TextView label1;
public ViewHolder1(View v) {
super(v);
label1 = (TextView) v.findViewById(R.id.text1);
}
public TextView getLabel1() {
return label1;
}
public void setLabel1(TextView label1) {
this.label1 = label1;
}
}
//相应的所有其他 viewHolders。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (viewType) {
case CHECKBOX:
View v1 = inflater.inflate(R.layout.layout_viewholder1, viewGroup, false);
viewHolder = new ViewHolder1(v1);
break;
case RADIOGROUP:
View v2 = inflater.inflate(R.layout.layout_viewholder2, viewGroup, false);
viewHolder = new ViewHolder2(v2);
break;
//其余情况如下。
NExt 将数据设置为视图
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case CHECKBOX:
ViewHolder1 vh1 = (ViewHolder1) viewHolder;
configureViewHolder1(vh1, position);
break;
case RADIOGROUp:
ViewHolder2 vh2 = (ViewHolder2) viewHolder;
configureViewHolder2(vh2, position);
break;
//Rest cases follow.
default:
RecyclerViewSimpleTextViewHolder vh = (RecyclerViewSimpleTextViewHolder) viewHolder;
configureDefaultViewHolder(vh, position);
break;
}
}
private void configureViewHolder1(ViewHolder1 vh1, int position) {
CheckBoxPojo user = (CheckBoxPojo) items.get(position);
if (user != null) {
vh1.getCheckBox1().setChecked(user.isChecked);
}
}
private void configureViewHolder2(ViewHolder2 vh2) {
//vh2.getImageView().setImageResource(R.drawable.sample_golden_gate);
Similarly rest follows.
}
大功告成!!!您可以以任何方式配置,可能有多少,它们可能有多随机。
参考:https://guides.codepath.com/android/Heterogenous-Layouts-inside-RecyclerView
编辑:
找出您添加的代码段中的问题。以下是问题:
case TITLE_VIEW: View v2 = inflater.inflate(R.layout.child_title, parent, false); viewHolder = new TitleHolder(v2); break; case INPUT: View v3 = inflater.inflate(R.layout.child_inputfield, parent, false); viewHolder = new TitleHolder(v3); break;
在这两种情况下,您都只使用标题持有人。