在滚动时将SwitchCompat状态保存在回收器视图中

时间:2018-05-06 20:32:42

标签: android android-recyclerview switchcompat

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

对此有何帮助?

我道歉因为现在无法发布部分代码,我会尽快发布,我现在就发布它以防万一有人在此之前通过这样的事情

谢谢

2 个答案:

答案 0 :(得分:0)

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

class ItemModel {
  String text;
  boolean on;
}

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

此模型包含一个字符串text,它反映了文本视图中的文本,以及一个反映开关状态的布尔值on。如果为true,则检查开关,如果为false,则取消选中。

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

现在让我们构建一个可以执行两项操作的适配器 - 单击开关时更新模型并告诉活动交换机已更改状态。这是实现此目的的一种方法:

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来通知侦听器有关交换机更改的信息。请注意,在方法OnCheckedChangeListener中,您不应再使用position,而是使用holder.getAdapterPosition,这一点非常重要。这将为您提供适配器数据列表中的正确位置。

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

在视图获得回收时移除OnCheckedChangeListener非常重要 - onViewRecycled。这可以避免在适配器在switchCompat中设置onBindViewHolder的值时弄乱计数。

以下是活动的示例:

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以更新活动中的文本视图。

布局文件在这里不应该相关,但是您可以想象活动的文本视图标识为count,而回收者视图的标识为recyclerview

希望这有帮助

答案 1 :(得分:0)

在适配器中添加以下方法后,它为我解决了

@Override
public int getItemViewType(int position) {

    return position;
}