【问题标题】:Saving SwitchCompat State in the recycler view while scrolling滚动时在回收站视图中保存 SwitchCompat 状态
【发布时间】:2018-05-06 20:32:42
【问题描述】:

我有一个recyclerview,其中的项目包含textViewswitchCompat。在同一个活动中,我还有一个textView,其中有一个数值。任务是当switchCompat打开recyclerview上方的文本视图时,其中包含的数值应该增加recyclerviewtextview中的值。我已经这样做了,但是当在 recyclerview 中滚动时,switchCompat 回到默认状态并且数字 textview 的值返回到它的旧值,

有什么帮助吗?

对于现在无法发布部分代码,我深表歉意,我会尽快发布,我现在才发布,以防之前有人遇到过类似的情况

谢谢

【问题讨论】:

    标签: android android-recyclerview switchcompat


    【解决方案1】:

    Android 中回收器视图或任何适配器视图的关键是让适配器使您的模型适应视图。在您的情况下,您的视图是TextView 加上Switch,因此您的适配器必须使某些模型适应此视图。在这种情况下,我会选择这样一个简单的模型:

    class ItemModel {
      String text;
      boolean on;
    }
    

    为了简单起见,我省略了 getter 和 setter

    此模型包含一个字符串text,它反映了您的文本视图中的文本,以及一个布尔值on,它反映了开关的状态。当为真时,开关被选中,当它为假时,它被取消选中。

    有很多方法可以表示这个模型。我选择了这个,你可以选择其他的。关键是,您需要将状态保存在某处,这就是我所说的模型 - 视图模型。

    现在让我们构建一个适配器,它可以做两件事 - 当点击开关时更新模型并告诉 Activity 开关改变了状态。这是执行此操作的一种方法:

    public class ItemsAdapter extends 
      RecyclerView.Adapter<ItemsAdapter.ViewHolder> {
        @NonNull
        private final List<ItemModel> itemModels;
        @Nullable
        private OnItemCheckedChangeListener onItemCheckedChangeListener;
    
        ItemsAdapter(@NonNull List<ItemModel> itemModels) {
            this.itemModels = itemModels;
        }
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new ViewHolder(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item, parent, false));
        }
    
        @Override
        public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
            ItemModel item = itemModels.get(position);
            holder.text.setText(item.text);
            holder.switchCompat.setChecked(item.on);
    
            // Make sure we update the model if the user taps the switch
            holder.switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    int adapterPosition = holder.getAdapterPosition();
    
                    ItemModel tapped = itemModels.get(adapterPosition);
                    itemModels.set(adapterPosition, new ItemModel(tapped.text, isChecked));
    
                    if (onItemCheckedChangeListener != null) {
                        onItemCheckedChangeListener.onItemCheckedChanged(adapterPosition, isChecked);
                    }
                }
            });
        }
    
        @Override
        public void onViewRecycled(@NonNull ViewHolder holder) {
            super.onViewRecycled(holder);
    
            holder.switchCompat.setOnCheckedChangeListener(null);
        }
    
        @Override
        public int getItemCount() {
            return itemModels.size();
        }
    
        public void setOnItemCheckedChangeListener(@Nullable OnItemCheckedChangeListener onItemCheckedChangeListener) {
            this.onItemCheckedChangeListener = onItemCheckedChangeListener;
        }
    
        interface OnItemCheckedChangeListener {
            /**
             * Fired when the item check state is changed
             */
            void onItemCheckedChanged(int position, boolean isChecked);
        }
    
        class ViewHolder extends RecyclerView.ViewHolder {
            TextView text;
            SwitchCompat switchCompat;
    
            ViewHolder(View itemView) {
                super(itemView);
                text = itemView.findViewById(R.id.item_text);
                switchCompat = itemView.findViewById(R.id.item_switch);
            }
        }
    }
    

    有很多东西要消化,但让我们专注于重要的部分 - 方法onBindViewHolder。前 3 行是视图的经典循环。我们在正确的位置抓取模型,并在视图中设置与模型属性对应的元素。

    然后它变得更有趣。我们设置一个OnCheckedChangeListener 来在每次开关改变状态时更新模型和活动。前 3 行更改适配器中的模型,其余使用自定义接口 OnItemCheckedChangeListener 通知监听器有关开关更改。需要注意的是,在方法@​​987654330@ 中,您不应再使用position,而应使用holder.getAdapterPosition。这将为您提供适配器数据列表中的正确位置。

    由于现在适配器在数据列表中始终拥有正确的模型,因此每次调用方法onBindViewHolder 时适配器都知道如何设置视图。这意味着在滚动和回收视图时,它将保留data 列表中模型中每个项目的状态。

    当视图被回收时删除OnCheckedChangeListener 很重要 - onViewRecycled。这样可以避免适配器在onBindViewHolder 中设置switchCompat 的值时弄乱计数。

    以下是活动的示例:

    public class MainActivity extends AppCompatActivity {
        private int count = 0;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            List<ItemModel> data = new ArrayList<>();
    
            for (int i = 1; i <= 100; i++)
                data.add(new ItemModel("Item " + i, false));
    
            ItemsAdapter adapter = new ItemsAdapter(data);
    
            ((RecyclerView) findViewById(R.id.recyclerview)).setAdapter(adapter);
    
            final TextView countTextView = findViewById(R.id.count);
    
            drawCount(countTextView);
    
            adapter.setOnItemCheckedChangeListener(new ItemsAdapter.OnItemCheckedChangeListener() {
                @Override
                public void onItemCheckedChanged(int position, boolean isChecked) {
                    if (isChecked)
                        count++;
                    else
                        count--;
    
                    drawCount(countTextView);
                }
            });
        }
    
        private void drawCount(TextView countTextView) {
            countTextView.setText(String.valueOf(count));
        }
    }
    

    这段代码是为了演示这个想法,而不是跟随 :) 无论如何,我们设置所有初始状态,然后设置自定义侦听器OnItemCheckedChangeListener 以更新活动中的文本视图。

    布局文件在这里不应该相关,但您可以想象,活动有一个 ID 为 count 的文本视图和一个 ID 为 recyclerview 的回收器视图。

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      将以下方法添加到适配器后,它为我解决了:

      @Override
      public int getItemViewType(int position) {
      
          return position;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多