Android 中回收器视图或任何适配器视图的关键是让适配器使您的模型适应视图。在您的情况下,您的视图是 a TextView
plus a Switch
,因此您的适配器必须使某些模型适应该视图。在这种情况下,我会选择一个像这样的简单模型:
class ItemModel {
String text;
boolean on;
}
为简单起见,我省略了 getter 和 setter
该模型包含一个text
反映文本视图中文本的字符串和一个on
反映开关状态的布尔值。当为真时,开关被选中,当它为假时,它被取消选中。
有很多方法可以表示这个模型。我选择了这个,你可以选择其他的。关键是,您需要将状态保存在某处,这就是我所说的模型 - 视图模型。
现在让我们构建一个适配器,它可以做两件事——当点击开关时更新模型并告诉活动开关改变了状态。这是执行此操作的一种方法:
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 行是视图的经典循环。我们在正确的位置抓取模型并在视图中设置与模型属性相对应的元素。
然后它变得更有趣。我们设置 aOnCheckedChangeListener
以在每次开关更改状态时更新模型和活动。前 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
器以更新 Activity 中的文本视图。
布局文件在这里不应该相关,但是您可以想象活动有一个带有 id 的文本视图count
和一个带有 id 的回收器视图recyclerview
。
希望这可以帮助