Android RecyclerView实现多种item布局的方法

2020-10-28 18:42:44 浏览数 (1)

在项目中列表是基本都会用到的,然而在显示列表时,我们需要的数据可能需要不止一种item显示,对于复杂的数据就需要多种item,以不同的样式显示出来,这样效果是很棒的,我们先看一下效果

我们可以看到,这个RecyclerView中有多种item显示出来,那么具体怎么实现呢,其实在RecyclerView中,我们可以重写方法getItemViewType(),这个方法会传进一个参数position表示当前是第几个Item,然后我们可以通过position拿到当前的Item对象,然后判断这个item对象需要那种视图,返回一个int类型的视图标志,然后在onCreatViewHolder方法中给引入布局,这样就能够实现多种item显示了,讲了这么多我们看一下具体的例子

代码语言:javascript复制
@Override 
public int getItemViewType(int position) { 
  if(list.size() == 0){ 
    return EMPTY_VIEW; 
  } else if(list.get(position) == null){ 
    return PROGRESS_VIEW; 
  } else if(list.get(position).getType().equals(News.IMAGE_NEWS)){ 
    return IMAGE_VIEW; 
  } else { 
    return super.getItemViewType(position); 
  } 
} 

首先我们重写了getItemViewType这个方法,在这个方法中根据position对item对象做了一些判断,如果存储item对象的集合大小为空,返回空view标识(这里为1),如果item对象为null,返回进度条标识,这个主要是用于实现下拉加载更多,如果item对象类型属于图片类型,就返回图片类型对应的Item,这个就是效果图中的第一个Item类型,否则就是其它类型,也就是效果图中的另一种item布局,然后我们在onCreatViewHolder中具体的为每一种类型引入其布局

代码语言:javascript复制
@Override 
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
  View view; 
  if(viewType == PROGRESS_VIEW){ 
    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false); 
    return new ProgressViewHolder(view); 
  } else if(viewType == EMPTY_VIEW){ 
    return null; 
  } else if(viewType == IMAGE_VIEW){ 
    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_news_item, parent, false); 
    return new ImageViewHolder(view); 
  } else { 
    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false); 
    return new NewsViewHolder(view); 
  } 
} 

上面的代码就是具体为每种viewType引入其对应的布局,这样就基本实现了多种item布局,但是仅仅是这些还不够,因为我们还要对每种item设置数据,所以还要对每种item写一个VIewHolder来为item显示数据

代码语言:javascript复制
class NewsViewHolder extends RecyclerView.ViewHolder{  
  @BindView(R.id.news_title)TextView title; 
  @BindView(R.id.news_digest)TextView digest; 
  @BindView(R.id.news_time)TextView time; 
  @BindView(R.id.news_src)ImageView image;  
  public NewsViewHolder(View itemView) { 
    super(itemView); 
    ButterKnife.bind(this, itemView); 
  } 
} 
 
class ImageViewHolder extends RecyclerView.ViewHolder{  
  @BindView(R.id.news_title) TextView title; 
  @BindView(R.id.image_left) ImageView imageLeft; 
  @BindView(R.id.image_right) ImageView imageRight; 
  @BindView(R.id.image_middle) ImageView imageMiddle; 
  @BindView(R.id.news_time) TextView time;  
  public ImageViewHolder(View itemView) { 
    super(itemView); 
    ButterKnife.bind(this, itemView); 
  } 
} 
 
class ProgressViewHolder extends RecyclerView.ViewHolder {  
  @BindView(R.id.progressBar) ProgressBar progressBar; 
  @BindView(R.id.textView) TextView textView;  
  public ProgressViewHolder(View itemView) { 
    super(itemView); 
    ButterKnife.bind(this, itemView); 
  } 
} 

上面就是item对应的几个ViewHolder,判断viewHolder属于那种对象,然后在onBindViewHolder中根据对应的ViewHolder对其控件设置数据并显示

代码语言:javascript复制
@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 
  holder.itemView.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
      clickListener.onItemClick(v, position); 
    } 
  }); 
  if(holder instanceof NewsViewHolder){ 
    NewsViewHolder viewHolder = (NewsViewHolder)holder; 
    viewHolder.title.setText(list.get(position).getTitle()); 
    viewHolder.time.setText(list.get(position).getTime()); 
    /** 
     * Glide加载图片 
     */ 
    Glide.with(context).load(list.get(position).getImageUrl().get(0)) 
        .override(dpToPx(72), dpToPx(72)).centerCrop().into(viewHolder.image); 
    if(list.get(position).getType().equals(News.TEXT_NEWS)){ 
      viewHolder.digest.setText(list.get(position).getDigest()); 
    } else { 
      viewHolder.digest.setText(""); 
    } 
  } else if(holder instanceof ImageViewHolder){ 
    ImageViewHolder viewHolder = (ImageViewHolder)holder; 
    viewHolder.title.setText(list.get(position).getTitle()); 
    viewHolder.time.setText(list.get(position).getTime()); 
    setItemImage(viewHolder, list, position); 
  } else if(holder instanceof ProgressViewHolder){ 
    ProgressViewHolder viewHolder = (ProgressViewHolder)holder; 
    viewHolder.progressBar.setIndeterminate(true); 
 
  } 
} 

整个过程基本就是这样,这种方式在项目中经常会用到,我们就可以这样去处理,下拉加载更多就可以这样实现,在加载完数据后再往对象集合中传入null,然后判断如果出现null就加载progressBar布局,再加上Google官方的SwipeRefreshLayout,下拉刷新,上拉加载就搞定了,其实很容易,而且也有点Material Design 的感觉~~~~~~

看下Adapter的全部代码

代码语言:javascript复制
package com.zmt.e_read.Adapter;  
import android.content.Context; 
import android.support.v7.widget.RecyclerView; 
import android.util.DisplayMetrics; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.ImageView; 
import android.widget.TextView;  
import com.bumptech.glide.Glide; 
import com.zmt.e_read.Module.News; 
import com.zmt.e_read.Module.OnItemClickListener; 
import com.zmt.e_read.R; 
import com.zmt.e_read.Utils.ProgressViewHolder; 
import java.util.Collection; 
import java.util.Collections; 
import java.util.List; 
import butterknife.BindView; 
import butterknife.ButterKnife;  
/** 
* Created by Dangelo on 2016/9/27. 
*/ 
public class NewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder  { 
private final int EMPTY_VIEW = 1; 
private final int PROGRESS_VIEW = 2; 
private final int IMAGE_VIEW = 3; 
private Context context; 
private List<News  list; 
private OnItemClickListener clickListener; 
public NewsAdapter(Context context, List<News  list, OnItemClickListener clickListener) { 
this.context = context; 
this.list = list; 
this.clickListener = clickListener; 
} 
public void addOnItemClickListener(OnItemClickListener clickListener){ 
this.clickListener = clickListener; 
} 
@Override 
public int getItemViewType(int position) { 
if(list.size() == 0){ 
return EMPTY_VIEW; 
} else if(list.get(position) == null){ 
return PROGRESS_VIEW; 
} else if(list.get(position).getType().equals(News.IMAGE_NEWS)){ 
return IMAGE_VIEW; 
} else { 
return super.getItemViewType(position); 
} 
} 
@Override 
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
View view; 
if(viewType == PROGRESS_VIEW){ 
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false); 
return new ProgressViewHolder(view); 
} else if(viewType == EMPTY_VIEW){ 
return null; 
} else if(viewType == IMAGE_VIEW){ 
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_news_item, parent, false); 
return new ImageViewHolder(view); 
} else { 
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false); 
return new NewsViewHolder(view); 
} 
} 
@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 
holder.itemView.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
clickListener.onItemClick(v, position); 
} 
}); 
if(holder instanceof NewsViewHolder){ 
NewsViewHolder viewHolder = (NewsViewHolder)holder; 
viewHolder.title.setText(list.get(position).getTitle()); 
viewHolder.time.setText(list.get(position).getTime()); 
/** 
* Glide加载图片 
*/ 
Glide.with(context).load(list.get(position).getImageUrl().get(0)) 
.override(dpToPx(72), dpToPx(72)).centerCrop().into(viewHolder.image); 
if(list.get(position).getType().equals(News.TEXT_NEWS)){ 
viewHolder.digest.setText(list.get(position).getDigest()); 
} else { 
viewHolder.digest.setText(""); 
} 
} else if(holder instanceof ImageViewHolder){ 
ImageViewHolder viewHolder = (ImageViewHolder)holder; 
viewHolder.title.setText(list.get(position).getTitle()); 
viewHolder.time.setText(list.get(position).getTime()); 
setItemImage(viewHolder, list, position); 
} else if(holder instanceof ProgressViewHolder){ 
ProgressViewHolder viewHolder = (ProgressViewHolder)holder; 
viewHolder.progressBar.setIndeterminate(true); 
} 
} 
public void setItemImage(ImageViewHolder viewHolder, List<News  list, int position){ 
viewHolder.imageMiddle.setVisibility(View.VISIBLE); 
viewHolder.imageRight.setVisibility(View.VISIBLE); 
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 
if(list.get(position).getImageUrl().size() == 1){ 
Glide.with(context).load(list.get(position).getImageUrl().get(0)) 
.override(displayMetrics.widthPixels - dpToPx(10), dpToPx(90)) 
.centerCrop().into(viewHolder.imageLeft); 
viewHolder.imageMiddle.setVisibility(View.GONE); 
viewHolder.imageRight.setVisibility(View.GONE); 
} else if(list.get(position).getImageUrl().size() == 2){ 
int imageWidth = (displayMetrics.widthPixels - dpToPx(20)) / 2; 
Glide.with(context).load(list.get(position).getImageUrl().get(0)) 
.override(imageWidth, dpToPx(90)) 
.centerCrop().into(viewHolder.imageLeft); 
Glide.with(context).load(list.get(position).getImageUrl().get(1)) 
.override(imageWidth, dpToPx(90)) 
.centerCrop().into(viewHolder.imageMiddle); 
viewHolder.imageRight.setVisibility(View.GONE); 
} else if(list.get(position).getImageUrl().size()  = 3){ 
int imageWidth = (displayMetrics.widthPixels - dpToPx(30)) / 3; 
Glide.with(context).load(list.get(position).getImageUrl().get(0)) 
.override(imageWidth, dpToPx(90)) 
.centerCrop().into(viewHolder.imageLeft); 
Glide.with(context).load(list.get(position).getImageUrl().get(1)) 
.override(imageWidth, dpToPx(90)) 
.centerCrop().into(viewHolder.imageMiddle); 
Glide.with(context).load(list.get(position).getImageUrl().get(2)) 
.override(imageWidth, dpToPx(90)) 
.centerCrop().into(viewHolder.imageRight); 
} 
} 
@Override 
public int getItemCount() { 
return list.size(); 
} 
public int dpToPx(float dp){ 
float px = context.getResources().getDisplayMetrics().density; 
return (int)(dp * px   0.5f); 
} 
class NewsViewHolder extends RecyclerView.ViewHolder{ 
@BindView(R.id.news_title)TextView title; 
@BindView(R.id.news_digest)TextView digest; 
@BindView(R.id.news_time)TextView time; 
@BindView(R.id.news_src)ImageView image;  
public NewsViewHolder(View itemView) { 
super(itemView); 
ButterKnife.bind(this, itemView); 
} 
} 
class ImageViewHolder extends RecyclerView.ViewHolder{ 
@BindView(R.id.news_title) TextView title; 
@BindView(R.id.image_left) ImageView imageLeft; 
@BindView(R.id.image_right) ImageView imageRight; 
@BindView(R.id.image_middle) ImageView imageMiddle; 
@BindView(R.id.news_time) TextView time;  
public ImageViewHolder(View itemView) { 
super(itemView); 
ButterKnife.bind(this, itemView); 
} 
} 
class ProgressViewHolder extends RecyclerView.ViewHolder { 
@BindView(R.id.progressBar) ProgressBar progressBar; 
@BindView(R.id.textView) TextView textView;  
public ProgressViewHolder(View itemView) { 
super(itemView); 
ButterKnife.bind(this, itemView); 
} 
} 
}

项目地址:https://github.com/xiyouZmt/E-Read

最后说一下为什么为什么用RecyclerView取代ListView。

用过ListView的都知道,在ListView中若要复用视图缓存,就要在getView()方法中手动判断convertView是否为空,若不为空则复用视图缓存,若为空则重新加载视图,而RecyclerView相当于对ListView的Adapter进行了再次封装,把ListView手动判断是否有缓存的代码封装到RecyclerView内部,使这部分逻辑不可见,我们只需要通过getItemCount()方法告诉RecyclerView有多少项数据,然后在onCreateViewHolder()中加载item布局实例化ViewHolder,然后在onBindViewHolder()中完成数据的绑定即可。

以上就是本文的全部内容,希望对大家的学习有所帮助。

0 人点赞