【问题标题】:Radiogroup in recyclerview回收站视图中的 Radiogroup
【发布时间】:2016-02-02 07:07:38
【问题描述】:

我有一个 recyclerview,其中每个列表项都有一个带有 4 个单选按钮的单选组。如何正确存储每个无线电组的状态。 这是我的代码。在向上/向下滚动时,状态不正确。谢谢

public class ElementListAdapter extends RecyclerView.Adapter<ElementListAdapter.ViewHolder> {

    private List<Element> elements = new ArrayList<>();
    private Context context;

    private int[] state;

    public ElementListAdapter(Context context, List<Element> elements) {
        this.context = context;
        this.elements = elements;

        this.state = new int[elements.size()];
        Arrays.fill(this.state, -1);
    }

    @Override
    public ElementListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_layout, parent,
                false);

        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        final Element ele = elements.get(position);
        final String title = ele.getTitle();
        final String description = ele.getDescription();

        // Set text
        holder.tvTitle.setText(title);
        holder.tvDesciption.setText(description);

        if (ele.isHeader()) {                
            holder.radioGroup.setVisibility(View.GONE);
        } else {               
            holder.radioGroup.setVisibility(View.VISIBLE);
        }

        setRadio(holder, this.state[position]);



        holder.rb1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                state[position] = 0;
                setRadio(holder, state[position]);
            }
        });
        holder.rb2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                state[position] = 1;
                setRadio(holder, state[position]);
            }
        });
        holder.rb3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                state[position] = 2;
                setRadio(holder, state[position]);
            }
        });
        holder.rb4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                state[position] = 3;
                setRadio(holder, state[position]);
            }
        });


    }

    private void setRadio(final ViewHolder holder, int selection) {

        System.out.println("SELECT:" + selection);
        RadioButton b1 = holder.rb1;
        RadioButton b2 = holder.rb2;
        RadioButton b3 = holder.rb3;
        RadioButton b4 = holder.rb4;

        b1.setChecked(false);
        b2.setChecked(false);
        b3.setChecked(false);
        b4.setChecked(false);

        if (selection == 0) b1.setChecked(true);
        if (selection == 1) b2.setChecked(true);
        if (selection == 2) b3.setChecked(true);
        if (selection == 3) b4.setChecked(true);
    }

    @Override
    public int getItemCount() {
        return elements.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        public View view;
        public TextView tvTitle;
        public TextView tvDesciption;

        public RadioGroup radioGroup;
        public RadioButton rb1, rb2, rb3, rb4;


        public ViewHolder(View itemView) {
            super(itemView);

            view = itemView;
            tvTitle = (TextView) itemView.findViewById(R.id.title);
            tvDesciption = (TextView) itemView.findViewById(R.id.description);

            radioGroup = (RadioGroup) itemView.findViewById(R.id.radioGroup);
            rb1 = (RadioButton) itemView.findViewById(R.id.rb1);
            rb2 = (RadioButton) itemView.findViewById(R.id.rb2);
            rb3 = (RadioButton) itemView.findViewById(R.id.rb3);
            rb4 = (RadioButton) itemView.findViewById(R.id.rb4);

        }
    }

}

【问题讨论】:

  • 视图持有者回收,所以你不能默认持有状态。一种解决方案是动态存储状态(检查适配器位置)并在 onBindViewHolder 中恢复它们。不要触发任何 onCheckChange

标签: android android-recyclerview android-radiogroup


【解决方案1】:

保存您的项目state 的最佳方法是将状态变量放在列表的item model 中,例如:在您的情况下为“元素”,而不是在onBindViewHolder 中根据您的模型设置状态,在您的案例:

改变这个:setRadio(holder, this.state[position]);

对此:setRadio(holder, elements.get(position).getState());

在 onClick 方法中

例如:对于第一个 改变这个: state[position] = 0; setRadio(holder, this.state[position]);

对此: elements.get(position).setState(0); setRadio(holder, elements.get(position).getState());

【讨论】:

  • 感谢您的回复。它似乎仍然不起作用:/
  • 我进行了建议的更改并删除了 setChecked(false),它似乎有效。非常感谢:)
【解决方案2】:

最好的方法和最有效的方法是简单地添加一个变量来保存选项(选择的单选按钮)到类。在 onClick() 之后,只需将选择的单选按钮分配给变量并获取它。

首先,在您的 Element 类中添加一个变量,用于存储选中的单选按钮选项。

那么,

public class ElementListAdapter extends RecyclerView.Adapter<ElementListAdapter.ViewHolder> {

private List<Element> elements = new ArrayList<>();
private Context context;

//instance of interface created
final private ListItemClickListener myOnClickListener;

private int[] state;

//create a interface which helps to communicates with your main activity
public interface ListItemClickListener
{
    void onListItemClick(int clickItemIndex,String optionSelected);
}
public ElementListAdapter(Context context, List<Element> elements) {
    this.context = context;
    this.elements = elements;

    this.state = new int[elements.size()];
    Arrays.fill(this.state, -1);
}

@Override
public ElementListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_layout, parent,
            false);

    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    final Element ele = elements.get(position);
    final String title = ele.getTitle();
    final String description = ele.getDescription();

    // Set text
    holder.tvTitle.setText(title);
    holder.tvDesciption.setText(description);

    if (ele.isHeader()) {                
        holder.radioGroup.setVisibility(View.GONE);
    } else {               
        holder.radioGroup.setVisibility(View.VISIBLE);
    }

  holder.setIsRecyclable(false);

  //here you check the option selected
    switch (Element.getUserOption()) {
           case "1":
                   holder.rb1.setChecked(true);
               break;
           case "2":
                   holder.rb2.setChecked(true);
               break;
           case "3":
                   holder.rb3.setChecked(true);
               break;
           case "4":
                   holder.rb4.setChecked(true);
               break;
           default:
               holder.radioGroup.clearCheck();
      }
}

@Override
public int getItemCount() {
    return elements.size();
}

//make sure to implement onClickListener here
public static class ViewHolder extends RecyclerView.ViewHolder implements View.onClickListener {

    public View view;
    public TextView tvTitle;
    public TextView tvDesciption;
    public int clickedCardPosition;

    public RadioGroup radioGroup;
    public RadioButton rb1, rb2, rb3, rb4;


    public ViewHolder(View itemView) {
        super(itemView);

        view = itemView;
        tvTitle = (TextView) itemView.findViewById(R.id.title);
        tvDesciption = (TextView) itemView.findViewById(R.id.description);

        radioGroup = (RadioGroup) itemView.findViewById(R.id.radioGroup);
        rb1 = (RadioButton) itemView.findViewById(R.id.rb1);
        rb2 = (RadioButton) itemView.findViewById(R.id.rb2);
        rb3 = (RadioButton) itemView.findViewById(R.id.rb3);
        rb4 = (RadioButton) itemView.findViewById(R.id.rb4);

        rb1.setOnClickListener(this);
        rb2.setOnClickListener(this);
        rb3.setOnClickListener(this);
        rb4.setOnClickListener(this);

    }


@Override
    public void onClick(View view) {

        int clickedCardPosition = getAdapterPosition();

        if(rb1.isPressed()) myOnClickListener.onListItemClick(clickedCardPosition, "1");
        if(rb2.isPressed()) myOnClickListener.onListItemClick(clickedCardPosition,"2");
        if(rb3.isPressed()) myOnClickListener.onListItemClick(clickedCardPosition,"3");
        if(rb4.isPressed()) myOnClickListener.onListItemClick(clickedCardPosition,"4");

    }

}
}

然后,在您分配适配器的活动中,实现接口。

//implement here
public class YourMainActivity extends AppCompatActivity implements 
recyclerAdapter.ListItemClickListener{
.
.
.
.
.
@Override
public void onListItemClick(int clickItemIndex, String optionSelected) {

       //Here assign the value to the Element Obj
        yourList.get(clickItemIndex).setUserOption(optionSelected);
        yourAdapter.notifyDataSetChanged();

}

}

【讨论】:

    【解决方案3】:

    这就是我所做的。在我的 onBindViewHolder

    if(visualScore[position] == 1 ){
                    holder.rg.check(R.id.rb_1);
                }else{
                    if(audioScore[position] == 1){
                        holder.rg.check(R.id.rb_2);
                    }else{
                        if(kinestScore[position] == 1){
                            holder.rg.check(R.id.rb_3);
                        }else{
                            holder.rg.clearCheck();
                        }
                    }
                }
                holder.rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
                        switch (checkedId) {
                            case (R.id.rb_1):
                                visualScore[position] = 1;
                                audioScore[position] = 0;
                                kinestScore[position] = 0;
                                break;
                            case (R.id.rb_2):
                                visualScore[position] = 0;
                                audioScore[position] = 1;
                                kinestScore[position] = 0;
                                break;
                            case (R.id.rb_3):
                                visualScore[position] = 0;
                                audioScore[position] = 0;
                                kinestScore[position] = 1;
                                break;
                        }
            });
    

    我在适配器类中将所有分数数组声明为私有全局方法。然后,当点击提交按钮时:

    int v = 0, a = 0, k = 0;
                        for (int i = 0; i < Questions.length; i++){
                            v += visualScore[i];
                            a += audioScore[i];
                            k += kinestScore[i];
                        }
    

    【讨论】:

    • 并不是说我的方法更好,但这是一种解决方法。当recyclerview被scolled时会触发onCheckedChanged,但是值还是和我们保存在数组中的一样