在 Android 开发中,多类型适配器(Multi-type Adapter)是一种常见的适配器模式,允许我们在一个 RecyclerView 中展示不同类型的数据。每个数据项可以根据需要展示不同的布局(ViewType),这种方式在社交应用、新闻应用或电商应用中非常常见,比如新闻列表中可能会包含标题、图片、文本、视频等多种内容类型。
Jetpack Compose 中也可以通过类似的方式实现多类型适配器,虽然 Compose 是声明式的,但我们仍然可以灵活地处理不同类型的数据。
以下是关于 RecyclerView 多类型适配器 和 Jetpack Compose 多类型适配器 的实现和示例。
1. RecyclerView 多类型适配器实现
1.1 设计一个多类型的数据模型
首先,我们需要一个包含不同类型数据的模型。假设我们有一个列表,每个列表项有三种类型:TEXT
、IMAGE
、VIDEO
。
public class Item {
public enum Type {
TEXT,
IMAGE,
VIDEO
}
public Type type;
public String data; // 该项的数据,如文本、图片URL或视频URL
// 构造函数
public Item(Type type, String data) {
this.type = type;
this.data = data;
}
}
1.2 创建适配器
在适配器中,我们会根据每个项的类型,选择不同的布局和 ViewHolder
。
public class MultiTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Item> itemList;
// 定义不同的布局类型
private static final int TYPE_TEXT = 0;
private static final int TYPE_IMAGE = 1;
private static final int TYPE_VIDEO = 2;
public MultiTypeAdapter(List<Item> itemList) {
this.itemList = itemList;
}
@Override
public int getItemViewType(int position) {
// 根据数据类型返回不同的 ViewType
switch (itemList.get(position).type) {
case TEXT:
return TYPE_TEXT;
case IMAGE:
return TYPE_IMAGE;
case VIDEO:
return TYPE_VIDEO;
default:
return -1;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_TEXT:
return new TextViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false));
case TYPE_IMAGE:
return new ImageViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false));
case TYPE_VIDEO:
return new VideoViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_video, parent, false));
default:
throw new IllegalArgumentException("Invalid view type");
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Item item = itemList.get(position);
switch (holder.getItemViewType()) {
case TYPE_TEXT:
((TextViewHolder) holder).bind(item);
break;
case TYPE_IMAGE:
((ImageViewHolder) holder).bind(item);
break;
case TYPE_VIDEO:
((VideoViewHolder) holder).bind(item);
break;
}
}
@Override
public int getItemCount() {
return itemList.size();
}
// 文本项的 ViewHolder
class TextViewHolder extends RecyclerView.ViewHolder {
TextView textView;
TextViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
void bind(Item item) {
textView.setText(item.data);
}
}
// 图片项的 ViewHolder
class ImageViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
ImageViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
}
void bind(Item item) {
// 加载图片(使用 Glide 或 Picasso 等库)
Glide.with(imageView.getContext()).load(item.data).into(imageView);
}
}
// 视频项的 ViewHolder
class VideoViewHolder extends RecyclerView.ViewHolder {
VideoView videoView;
VideoViewHolder(View itemView) {
super(itemView);
videoView = itemView.findViewById(R.id.videoView);
}
void bind(Item item) {
// 加载视频(使用 ExoPlayer 或 VideoView)
videoView.setVideoURI(Uri.parse(item.data));
videoView.start();
}
}
}
1.3 适配器使用
RecyclerView recyclerView = findViewById(R.id.recyclerView);
MultiTypeAdapter adapter = new MultiTypeAdapter(createItems());
recyclerView.setAdapter(adapter);
private List<Item> createItems() {
List<Item> items = new ArrayList<>();
items.add(new Item(Item.Type.TEXT, "This is a text item"));
items.add(new Item(Item.Type.IMAGE, "https://example.com/image.jpg"));
items.add(new Item(Item.Type.VIDEO, "https://example.com/video.mp4"));
return items;
}
在这个例子中,我们通过 getItemViewType
来判断每个项的类型,然后在 onCreateViewHolder
中为不同类型的项创建不同的 ViewHolder
。每个 ViewHolder
负责处理不同类型的布局。
2. Jetpack Compose 多类型适配器实现
在 Jetpack Compose 中,我们使用 LazyColumn
或 LazyRow
作为 RecyclerView 的替代,来展示多种类型的列表项。我们可以通过条件判断来确定每个项的类型,并渲染不同的 UI 组件。
2.1 定义数据模型
sealed class Item {
data class TextItem(val text: String) : Item()
data class ImageItem(val imageUrl: String) : Item()
data class VideoItem(val videoUrl: String) : Item()
}
2.2 创建 LazyColumn
多类型适配器
@Composable
fun MultiTypeAdapter(items: List<Item>) {
LazyColumn {
items(items) { item ->
when (item) {
is Item.TextItem -> TextItemView(item)
is Item.ImageItem -> ImageItemView(item)
is Item.VideoItem -> VideoItemView(item)
}
}
}
}
@Composable
fun TextItemView(item: Item.TextItem) {
Text(text = item.text, style = MaterialTheme.typography.h6)
}
@Composable
fun ImageItemView(item: Item.ImageItem) {
Image(painter = rememberImagePainter(item.imageUrl), contentDescription = null)
}
@Composable
fun VideoItemView(item: Item.VideoItem) {
// 可以使用 ExoPlayer 或其他 Compose 插件来播放视频
// 示例仅为占位符
Text(text = "Video Item: ${item.videoUrl}")
}
2.3 使用 LazyColumn
展示多类型数据
@Composable
fun MultiTypeList() {
val items = listOf(
Item.TextItem("This is a text item"),
Item.ImageItem("https://example.com/image.jpg"),
Item.VideoItem("https://example.com/video.mp4")
)
MultiTypeAdapter(items = items)
}
3. 总结
- RecyclerView 中的多类型适配器:通过
getItemViewType()
来判断每个项的类型,适配不同的布局,并在onCreateViewHolder
中根据不同的 ViewType 来创建不同类型的ViewHolder
。 - Jetpack Compose 中的多类型适配器:通过
LazyColumn
和when
表达式来处理不同类型的列表项,可以根据每个项的类型展示不同的 UI 组件。
这种方式在显示复杂的数据结构时非常有用,能够灵活地展示不同类型的内容。
发表回复