【问题标题】:Checked RadioButton Recycling选中的 RadioButton 回收
【发布时间】:2019-03-02 12:47:42
【问题描述】:

我正在以编程方式将无线电组添加到我的 recyclerview 中,它工作正常。 但是当我检查它并滚动 recyclerview 时,它会丢失已检查的收音机。

我见过很多解决方案的方法和示例,但我无法实现。已经连续好几天了。

我正在将选中的收音机保存在模型中,如下面的代码所示。

适配器:

@Override
public void onBindViewHolder(final NROptionLineHolder holder, int position) {

    holder.priceGroup.removeAllViews();
    holder.priceGroup.setOnCheckedChangeListener(null);

    int id = (position+1)*100;
    checklistModel = mChecklists.get(position);
    holder.packageName.setText(checklistModel.getTitle());

    for(String price : checklistModel.getQuestions()){
        RadioButton rb = new RadioButton(NROptionLineAdapter.this.context);
        rb.setId(id++);
        rb.setText(price);
        holder.priceGroup.addView(rb);
    }
    holder.priceGroup.check(checklistModel.getSelectedId());

    holder.priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            checklistModel.setSelectedId(checkedId);
            Log.d(TAG, "onCheckedChanged: " + checkedId);
        }
    });

}

持有人

    OnNROptionListener onNROptionListener;

    public NROptionLineHolder(View itemView, OnNROptionListener onNROptionListener) {
        super(itemView);

        packageName = itemView.findViewById(R.id.package_name);
        priceGroup = itemView.findViewById(R.id.price_grp);

//        priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
//            @Override
//            public void onCheckedChanged(RadioGroup radioGroup, int i) {
//
//                Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
//            }
//        });

        this.onNROptionListener = onNROptionListener;
        itemView.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        onNROptionListener.onNROptionClick(getAdapterPosition());
    }

    public interface OnNROptionListener {
        void onNROptionClick(int position);
    }
}

编辑 1 - 广播组

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/package_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <RadioGroup
        android:id="@+id/price_grp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/package_name"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:orientation="horizontal"/>
</android.support.constraint.ConstraintLayout>

编辑 2

根据要求,这是我的 ChecklistActivity 中的重要代码

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_checklist);

    intent = getIntent();
    size = intent.getIntExtra("size", 0);
    nr = intent.getIntExtra("nr", 0);

    Log.d(TAG, "Checklist Activity - Qtd Questões: " + size);
    Log.d(TAG, "Checklist Activity - NR: " + nr);

    btnSaveCheck = findViewById(R.id.btnSaveChecklist);

    mRecyclerView = findViewById(R.id.package_lst);
    setupRecycler();

    btnSaveCheck.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(getApplicationContext(), "Sucesso", Toast.LENGTH_SHORT).show();
        }
    });
}

private void setupRecycler() {

    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    mRecyclerView.setLayoutManager(layoutManager);

    setupList();

    mAdapter = new NROptionLineAdapter(data, this, getApplication());
    mRecyclerView.setAdapter(mAdapter);

}

private void setupList(){
    data = new ArrayList<>();

    class setupList extends AsyncTask<Void, Void, List<MRNrOption>> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected List<MRNrOption> doInBackground(Void... voids) {

            list = DatabaseClient
                    .getInstance(getApplicationContext())
                    .getAppDatabase()
                    .mrNrOptionDAO()
                    .loadAllByNRId(nr);
            return list;

        }

        @Override
        protected void onPostExecute(List<MRNrOption> list) {
            super.onPostExecute(list);

            List<String> priceList = new ArrayList<>();
            priceList.add("Sim");
            priceList.add("Não");
            priceList.add("Não se Aplica");

            for (int i=0; i<list.size(); i++) {
                Log.d(TAG, "NRs Activity - Adding To List: " + list.get(i).getTitle());
                data.add(new Checklist(
                        list.get(i).getTitle(),
                        priceList)
                );

                mAdapter.notifyDataSetChanged();
            }

        }
    }

    setupList lm = new setupList();
    lm.execute();
}

编辑 3 - 重要

RadioGroups 和 RadioButtons 是以编程方式生成的,因为我从服务器获取所有问题,问题的数量取决于用户之前的选择,这就是我需要这种方式的原因。

编辑 4

GIF to enhance the problem visualization

EDIT 5 - 清单模型类

    public class Checklist {

    String title;
    List<String> questions;
    boolean isRadioButtonAdded;
    int selectedId;

    public Checklist(String title, List<String> questions) {
        this.title = title;
        this.questions = questions;
    }

    public Checklist(){}

    public boolean getIsAdded(){
        return isRadioButtonAdded;
    }

    public void setIsAdded(boolean isAdded){
        this.isRadioButtonAdded = isAdded;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<String> getQuestions() {
        return questions;
    }

    public void setQuestions(List<String> questions) {
        this.questions = questions;
    }

    public int getSelectedId() {
        return selectedId;
    }

    public void setSelectedId(int selectedId) {
        this.selectedId = selectedId;
    }
}

【问题讨论】:

  • 单选按钮是否使用样式?如果是,请分享。
  • @miladsalimi 查看我的编辑
  • 也请分享您的片段或活动
  • @miladsalimi 已更新
  • mChecklists.get(position).setSelectedId(checkedId) 你能在 onCheckedChanged 中试试吗?

标签: android android-recyclerview android-radiogroup


【解决方案1】:

虽然我不确定这是否会解决您的问题,但作为一种优化也是一个好习惯,您应该将侦听器附加到 onCreateViewHolder 而不是 onBindViewHolder 这可以防止创建多个对象为听众。

你为什么不把这段代码移到onCreateViewHolder里面

你拥有的视图持有者内的这个块:

priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            checklistModel.setSelectedId(checkedId);
            Log.d(TAG, "onCheckedChanged: " + checkedId);
        }
    });

【讨论】:

  • @Alan 您能否尝试记录您生成的idselectedId 的值,也许您拥有的算法正在生成错误的值,如果是这样,您可以尝试使用holder.adapterPosition
  • 为 id 和 selectedId 生成的值符合预期。
【解决方案2】:

尝试将您的 setOnCheckedChangeListener 代码移动到 ViewHolder 并在此处更新您的 mCheckList


priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
        mCheckList.get(getAdapterPosition()).setSelectedId(checkedId);
        Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
}});

主要问题是您没有更新正确的项目状态。当您单击单选按钮时,它将仅更新最后一个项目onBindViewHolder,因为 checklistModel 仅保存最后一个引用。要解决此问题,您始终需要在侦听器中访问 mainList。

【讨论】:

  • 我做到了,但我仍然丢失无线电检查。
  • 什么是setSelectedId
【解决方案3】:

当 onClick 事件发生时,将单选按钮的选中/未选中状态保存到您的模型(即列表中的项目应该有一个字段)。绑定 ViewHolder 时,请确保将复选框的值设置为您保存在模型中的任何值。

【讨论】:

    【解决方案4】:

    独特的工作解决方案是在 ViewHolder 中将 RecyclerView 设置为不可回收。

    this.setIsRecyclable(false);
    

    【讨论】:

    • 这会破坏RecyclerView的目的
    • 我知道它的作用。如果它不是一个选项,它不应该存在。您可以添加一个有用的答案。
    • 这更像是一种变通方法而不是解决方案。您应该在单选按钮的 onCheck 回调中更新您的 checkList 并调用适配器 notifyDataSetChanged
    • 我之前做过,但它不起作用。我有其他 recyclerview 按预期工作,但是这个有这种数据的那个不起作用。
    • @Alan 您可以尝试调试您的适配器并检查您的列表是否已更新。这值得一看,因为 onBindViewHolder 中的侦听器总是有问题
    【解决方案5】:

    下面的代码怎么样?

    适配器:

    由于视图被回收,我以为唯一id是错误的。

    int id = (position+1)*100;
    

    int id = 1;
    

    【讨论】:

    • 没有区别,同样的事情发生。
    • 在上面的代码之外,如果注释掉这段代码,会有什么变化呢? 适配器: //holder.priceGroup.removeAllViews(); 但是,ID 是资源 ID。由于它可能与单选按钮以外的资源 ID 重叠,我认为最好在 XML 中定义单选按钮。
    • 不可能在 XML 中定义单选按钮,因为它取决于问题的数量,如果我有 3 个来自服务器的问题,我需要 3 个 RadioGroups,里面有 3 个 RadioButtons。如果问题的数量发生变化,那么 RadioGroup 的数量也会发生变化。通过删除“removeAllViews()”,它会继续创建单选按钮,例如每个问题六个。
    • 我知道单选按钮的数量需要是动态的。将下面的代码放在 for 语句之外会有什么结果? 适配器: holder.priceGroup.check(checklistModel.getSelectedId());
    • 已经在外面for语句了,我会更新问题,我会尝试添加一个gif来帮助可视化。
    【解决方案6】:

    recyclerview 的工作方式是,当您向下或向上滚动直到视图不可见时,它会存储状态,但是当您向下滚动 recyclerview 或向上滚动 recyclerview 时,它会破坏该行并将新行放入其中position.so 整个行的视图将被破坏。

    该问题的解决方案是您将另一个变量添加到您正在使用的列表中,当单选按钮更改状态时,您存储数据并继续前进。 在您的数据模型类中像这样 而在 Model Class 中,您可以定义 recyclerview 正在使用哪个列表。

    Boolean is stateclicked;
    int state position;
    

    在 OnBindViewholder 中,您可以获取此数据的值。如果值为 null 则未单击,如果单击则将布尔值更改为 yes 并将状态值放入整数

    【讨论】:

      猜你喜欢
      • 2011-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-21
      • 2012-05-03
      • 2014-12-21
      相关资源
      最近更新 更多