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

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

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

@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中具体的为每一种类型引入其布局

@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显示数据

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对其控件设置数据并显示

@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的全部代码

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)

相关推荐

  • Android RecyclerView显示Item布局不一致解决办法

    RecyclerView显示Item布局不一致 在自定义RecyclerAdapter的时候,在重写onCreateViewHolder方法是使用了 @Override public H onCreateViewHolder(ViewGroup parent, int viewType) { View view=View.inflate(context,layoutId,null); return view; } 进行生成布局,结果发现生成的布局没有LayoutParams.以前自定义View的

  • RecyclerView的使用之多种Item加载布局

    本文给大家介石介绍下如何利用RecyclerView实现多Item布局的加载,多Item布局的加载的意思就是在开发过程中List的每一项可能根据需求的不同会加载不同的Layout. 下面给大家展示下演示效果图: * 图片资源版权归属于Facebook dribbble RecyclerView实现加载不同的Layout的核心就是在Adapter的onCreateViewHolder里面去根据需求而加载不同的布局. 具体的实现步骤:(以Android Studio作为开发工具) 1:Gradle配

  • Recyclerview添加头布局和尾布局、item点击事件详解

    简介: 本篇博客主要包括recyclerview添加多种布局以及添加头布局和尾布局,还有item点击事件 思路: 主要重写Recyclerview.Adapter中的一些方法 1.public int getItemCount()  item熟练  +2(头布局和尾布局) 2.public int getItemViewType(int position)   判断position 设置itemType 3.创建不同的ViewHolder,分别用来加载头布局,正常布局,尾布局 4.public

  • Android 中RecyclerView多种item布局的写法(头布局+脚布局)

    RecyclerView多个item布局的写法(头布局+脚布局) 上图 github 下载源码 Initial commit第一次提交的代码,为本文内容 以下的为主要代码,看注释即可,比较简单 MainActivity 含上拉加载更多 package com.anew.recyclerviewall; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivi

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

    在项目中列表是基本都会用到的,然而在显示列表时,我们需要的数据可能需要不止一种item显示,对于复杂的数据就需要多种item,以不同的样式显示出来,这样效果是很棒的,我们先看一下效果 我们可以看到,这个RecyclerView中有多种item显示出来,那么具体怎么实现呢,其实在RecyclerView中,我们可以重写方法getItemViewType(),这个方法会传进一个参数position表示当前是第几个Item,然后我们可以通过position拿到当前的Item对象,然后判断这个item对

  • Android开发之计算器GridLayout布局实现方法示例

    本文实例讲述了Android开发之计算器GridLayout布局实现方法.分享给大家供大家参考,具体如下: 运行效果: Demo 下载地址:https://github.com/LonglyWolf/Calculator 或者点击此处本站下载. 按钮布局实现: 一个Linearlayout 嵌套三个TextView 最下方的显示当前计算式.上面为先前的计算式. Gridview 网格布局排布按钮 <?xml version="1.0" encoding="utf-8&q

  • Android RecyclerView的卡顿问题的解决方法

    RecyclerView为什么会卡 RecyclerView作为v7包的新控件,自从推出就广受Android Developer们欢迎,实际上它已经取代了ListView和GridView两位老前辈的地位.然而不少亲们想必也已经发现了:没有优化过的Recycler性能很poor.上一篇博主使用的item也仅仅是一个图两串字而已,结果一滑动就卡的要命,不能忍! 那么why?回想在用ListView和GridView的adapter时,我们是用一种叫ViewHolder的自定义类(容器)来实现优化的

  • android RecyclerView实现条目Item拖拽排序与滑动删除

    效果演示 需求和技术分析 RecyclerView Item拖拽排序::长按RecyclerView的Item或者触摸Item的某个按钮. RecyclerView Item滑动删除:RecyclerView Item滑动删除:RecyclerView的Item滑动删除. 实现方案与技术 利用ItemTouchHelper绑定RecyclerView.ItemTouchHelper.Callback来实现UI更新,并且实现动态控制是否开启拖拽功能和滑动删除功能. 实现步骤 继承抽象类ItemTo

  • Android RecyclerView添加头部和底部的方法

    如果只是想添加头部,可是使用GitHub里面这个项目,它可以为LinearLayoutManager,GridLayoutManager ,StaggeredGridLayoutManager布局的RecyclerView添加header.使用起来也十分简单: 只需将RecyclerViewHeader布局放在RecyclerView的上层. <FrameLayout android:layout_width="match_parent" android:layout_heigh

  • Android RecyclerView加载不同布局简单实现

    前言 关于RecyclerView的使用这里就不在赘述了,相信网上一搜一大把(本人之前的文章也有简单的使用介绍),这次我们讲的是RecyclerView在使用的过程中,有时候会根据不同的位置加载不同的布局的简单实现,这里只是起到抛砖引玉的作用 效果图 设计思想  •重写RecyclerView.Adapter的getItemViewType(int position), 在此方法中根据不同的position,设置不同的ViewType  •编写具体的RecyclerView.ViewHolder

  • Android RecyclerView使用GridLayoutManager间距设置的方法

    使用RecyclerView设置间距,需要重写RecyclerView.ItemDecoration这个类.有如下的效果图需要实现,间距只有中间的格子和底部的格式之间有. 实现方法很简单,因为这个效果是每一行有3个格子,只要每行的第一个格式左边间距为0即可以.其他都设置左边距和底部距离. 代码如下: public class SpaceItemDecoration extends RecyclerView.ItemDecoration { private int space; public Sp

  • Android编程之代码创建布局实例分析

    本文实例讲述了Android编程之代码创建布局使用方法.分享给大家供大家参考,具体如下: 大概描述一下效果:最外层是一个 RelativeLayout 里面有自定义个LinearLayout,每个LinearLayout有两个TextView.that's it !!! private void initView() { // 获取xml的RelativeLayout layout = (RelativeLayout) findViewById(R.id.liner); for (int i =

随机推荐