RecyclerView+SwipeRefreshLayout优雅的实现封面式列表

初衷

Hi,i'm Rover Van.在最近的Android开发中呢,我想要实现一个图片式的list列表,并带有下拉刷新功能,具体如下图的样式。
这要是在之前一般都是用ListView实现的,在2014年 Google I/O 推出的RecyclerView到了去年才渐渐被人重视并使用,比起ListView,RecycleView显得非常艺术,更加灵活。主要表现在性能,动画,自定义性要比ListView优越的多,Google官方都提倡以RecyclerView替代ListView。
SwipeRefreshLayout是Google一个官方的下拉刷新控件,自带了一个非常简洁的下拉动画效果,这是Google官方的API文档
下面我写一个Demo将这两者都结合起来应用。

布局文件XML

1.添加SwipeRefreshLayout与RecyclerView控件

在这里我直接新建了一个空白的Project来作Demo,在activity_main.xml中添加两个控件布局

<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/layout_refresh_t"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/list_post_t"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fadingEdge="none" />
</android.support.v4.widget.SwipeRefreshLayout>

2.新建条目布局item

新建一个item_list.xml文件,将一个条目的样式布局写好,下面贴上我的代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="270dp"
    android:orientation="vertical"
    >
  <ImageView
      android:id="@+id/imageview"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:scaleType="fitXY"
      android:foreground="@android:color/black"
      android:background="@android:color/black"
      android:src="@android:color/black"
      android:clickable="false"
      />

  <TextView
      android:id="@+id/tilte"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_above="@+id/cate_and_length"
      android:layout_marginBottom="14dp"
      android:layout_marginLeft="10dp"
      android:textColor="@android:color/white"
      android:textSize="14dp"
      android:textStyle="bold"
      />

  <TextView
      android:id="@+id/cate_and_length"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_marginBottom="16dp"
      android:layout_marginLeft="10dp"
      android:textColor="@android:color/white"
      android:textSize="12dp"
      />
</RelativeLayout>

新建了三个控件,ImageView用来放置图片,第一个TextView作为标题,第二个TextView作为分类和时长。至于大小和相对位置就通过自己的喜好进行调整了
布局文件到这里就基本结束,下一步应用重点。

数据类(Bean)

这个时候就新建对应的bean类,这个就根据项目与分类的不同自己确定,在这里我新建了一个List类,出于效果需要,我暂时只是添加了几个成员变量。

public class VideoInfo {

    private String title;
    private String cate;
    private String length;
    private String imgurl;

    ... ...
}

RecyclerViewAdapter

和ListView一样,RecyclerView也需要一个适配器(Adapter)来作为连接数据和View的桥梁。在这里我推荐一一个在Github RecyclerViewAdapter Star数排名第四的BaseRecyclerViewAdapterHelper,有非常详细的中文版文档,所以其优势和具体用法请大家看其文档,这里我只点出实现本次主题所需要的几个功能点。

1.导入BaseRecyclerViewAdapterHelper 包

在 build.gradle(注意是project那个) 的 repositories 添加:

 allprojects {
    repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}

然后在build.gradle(注意是module:app那个)的 dependencies添加:

dependencies {
        compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:v1.9.7'
}

2.构建Adapter

自定义的Adapter要继承自BaseQuickAdapter,泛型是自己的bean类,其余的就是照着其文档的使用方法调用并赋值,其中调用到的Glide方法有机会我会在我下一篇博文详写。现在只需要在build.gradle(注意是module:app那个)的 dependencies添加:

dependencies {
        compile 'com.github.bumptech.glide:glide:3.7.0'
}    

即可使用下面的方面,我也贴上我的ListAdapter代码供大家参考。

public class ListAdapter extends BaseQuickAdapter<VideoInfo> {

public ListAdapter(Context context,List<VideoInfo> data)            {
    super(R.layout.item_list,data);
}

@Override
protected void convert(BaseViewHolder baseViewHolder, VideoInfo videoInfo) {

    baseViewHolder.setText(R.id.tilte,videoInfo.getTitle());//设置标题
    String cate_and_length = videoInfo.getCate()+"/"+videoInfo.getLength();
    baseViewHolder.setText(R.id.title,cate_and_length);//设置分类和时长
    Glide.with(mContext)
            .load(videoInfo.getImgurl())
            .error(android.R.color.black)
            .crossFade()
            .into((ImageView) baseViewHolder.getView(R.id.imageview));//设置封面图片
    }
}

Activity

接下来只要在Activity将这个Adapter实例化即可,只是作为demo用,所以这里我写了一个requestForData()方法来模拟请求服务器数据。

public class MainActivity extends AppCompatActivity {
RecyclerView listPost;
ListAdapter listAdapter;
List<VideoInfo> data= new ArrayList<VideoInfo>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //该方法模拟从服务器请求数据
    requestForData(data);

    listPost = (RecyclerView) findViewById(R.id.recyclerview);
    listAdapter = new ListAdapter(this,data);
    listAdapter.openLoadMore(10, true);
    listAdapter.openLoadAnimation();

    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    listPost.setLayoutManager(linearLayoutManager);
    listPost.setAdapter(listAdapter);
}

List<VideoInfo> requestForData(List<VideoInfo> data){

    data.add(new VideoInfo("demo1","cate1","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/red.jpg"));
    data.add(new VideoInfo("demo2","cate2","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/black.jpg"));
    data.add(new VideoInfo("demo3","cate1","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/orange.jpg"));
    data.add(new VideoInfo("demo4","cate2","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/red.jpg"));
    data.add(new VideoInfo("demo5","cate1","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/black.jpg"));
    data.add(new VideoInfo("demo6","cate2","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/orange.jpg"));
    data.add(new VideoInfo("demo7","cate1","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/red.jpg"));
    data.add(new VideoInfo("demo8","cate2","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/black.jpg"));
    data.add(new VideoInfo("demo9","cate1","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/orange.jpg"));
    data.add(new VideoInfo("demo10","cate2","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/red.jpg"));
    data.add(new VideoInfo("demo11","cate1","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/black.jpg"));
    data.add(new VideoInfo("demo12","cate2","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/orange.jpg"));
    return data;
    }
}

在这里我用一个ArrayList来存放数据,再作为参数传到实例化ListAdapter的方法里,而 openLoadAnimation() 方法用来开启动画与自定义动画,这个在文档里也有详细说明,这里不再赘述。
到这里为止,关于RecaclerView的应用就差不多了,接下来我们来加上SwipeRefreshLayout控件

SwipeRefreshLayout

由于SwipeRefreshLayout本身就是Widget的子类,所以主要是对应方法上的重写以及在onCreate将它实例化。

1.引用接口

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener{
...
}

2.实现接口方法onRefresh()

@Override
public void onRefresh() {
    List<VideoInfo> data = new ArrayList<VideoInfo>();
    data.add(new VideoInfo("我是刷新出来的","cate1","4'12","http://ossfordemo.oss-cn-shenzhen.aliyuncs.com/android/rvwsrl/orange.jpg"));
    data = requestForData(data);
    listAdapter.setNewData(data);
    listAdapter.openLoadMore(10, true);
    refreshLayout.setRefreshing(false);
}

这里主要看最后几个方法的调用,和Adapter搭配使用,我添加了一个新的对象来验证刷新成功。运行后可以看到一个标题为("我是刷新出来的")的新item。

3.在onCreate()方法实例化该控件

主要是绑定xml控件和设置监听,已经将刚刚新增的代码行注释出来。

RecyclerView listPost;
ListAdapter listAdapter;
List<VideoInfo> data= new ArrayList<VideoInfo>();
SwipeRefreshLayout refreshLayout;//new

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //该方法模拟从服务器请求数据
    requestForData(data);

    listPost = (RecyclerView) findViewById(R.id.recyclerview);
    refreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefreshlayout);//new

    listAdapter = new ListAdapter(this,data);
    listAdapter.openLoadMore(10, true);
    listAdapter.openLoadAnimation();

    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    listPost.setLayoutManager(linearLayoutManager);
    listPost.setAdapter(listAdapter);

    refreshLayout.setOnRefreshListener(this);//new

}

最后

到这里已经接近项目的尾声了,不过还要在Androidmanifest里添加访问网络的权限,然后,Done!
这个Demo偏侧重如何将这个UI设计出来并实现,还有一些例如多组件的RecyclerView,添加控件的头部尾部,各种动画,item的监听都还没有实现,在Cymchad的github中关于BaseRecyclerViewAdapterHelper已经写的非常好,我们只要根据文档简单的调用方法就可以实现我们需要的多种功能。

Github

这个项目的Demo已经在我的Github上开源,有兴趣的朋友欢迎Star或Download,一起交流和学习噢。

Contact me

如果有什么错误或者建议 OR 如果需要请教关于本主题的实现问题
欢迎来邮与我交流和讨论!
Email:atrovervan@gmail.com

2016-08-08 15:05 353
Comments
Write a Comment