一、前提
RecyclerView能够灵活实现大数据集的显示,视图的复用管理里ListView更好,能够显示列表,网格,瀑布流等形式,且不同的ViewHolder能够实现item多元化的功能,但是使用起来稍微麻烦一点,并且没有类似的监听事件,需要开发者自己实现
二、目标
RecyclerView
三、内容
1、首先现在buildgrade下添加以下代码,必须添加,否则不能使用RecyclerView
compile 'com.android.support:design:25.3.1'
2、在MainActivity中编写一个RecyclerView组件
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</android.support.v7.widget.RecyclerView>
3、再写一个xml文件用来显示组件,跟ListView一样,在这里只编写一个TextView
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#000000"
android:textSize="20sp"
/>
4、MainActivity:
(1)在布局文件中找到RecyclerView
(2)定义一个列表,其中添加数据
(3)向RecyclerView中利用setLayoutManager设置布局管理器
(4)为RecyclerView创建一个适配器
package com.mingrisoft.recyclerview;
import android.graphics.Rect;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class LinearRecyclerViewActivity extends AppCompatActivity {
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_linear_recycler_view);
//四大组成
//LayoutManager:Item的布局。
//Adapter:为Item提供数据。
//Item Decoration:Item之间的Divider。
//Item Animator:添加、删除Item动画。
List<String> data=initData();
recyclerView= (RecyclerView) findViewById(R.id.rv);
//RecyclerView提供了三种布局管理器:
//LinerLayoutManager 以垂直或者水平列表方式展示Item
//GridLayoutManager 以网格方式展示Item
//StaggeredGridLayoutManager 以瀑布流方式展示Item
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//recyclerView.addItemDecoration(new MyItemDivider(this,R.drawable.style));
recyclerView.setAdapter(new LinearAdapter(this,data));
}
private List<String> initData() {
List<String> datas=new ArrayList<String>();
for(int i=0;i<20;i++){
datas.add("items:"+i);
}
return datas;
}
}
5、新建一个Adapter类继承RecyclerView.Adapter:
(1)Adapter的构造方法,其中输入上下文对象,数据一类的
LayoutInflater
1.1、首先需要获得其实例,通过.from(context)方法
1.2、其次通过inflate(R.id.xxx,parent,false)方法找到布局文件,并且实例化
(2)创建一个ViewHolder继承与RecyclerView.ViewHolder,其中要添加在布局文件中编写好的组件,创建构造方法,在其中找到组件的位置
(3)onCreateViewHolder方法,为每一个item设置一个view,返回的对象是ViewHolder(layoutinflater.inflate(R.id.xxx,parent,false))
(4)onBindViewHolder适配数据、通过holder.组件.setText(data.get(position))
(5)getItemCount()返回列表的长度data.size()
package com.mingrisoft.recyclerview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
/**
* Created by Administrator on 2020/4/5/005.
*/
public class LinearAdapter extends RecyclerView.Adapter<LinearAdapter.LinearViewHolder> {
private List<String> datas;
private Context contexts;
private LayoutInflater layoutInflater;
public LinearAdapter(Context context,List<String> data){
this.datas=data;
this.contexts=context;
layoutInflater=layoutInflater.from(contexts);
}
class LinearViewHolder extends RecyclerView.ViewHolder{//创建ViewHolder
private TextView textView;
public LinearViewHolder(View itemView) {
super(itemView);
textView= (TextView) itemView.findViewById(R.id.text);
}
}
@Override
public LinearAdapter.LinearViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {//为每一个Item inflater出个view
return new LinearViewHolder(layoutInflater.inflate(R.layout.linear_item,parent,false));
}
@Override
public void onBindViewHolder(LinearAdapter.LinearViewHolder holder, final int position) {//适配数据到view中
holder.textView.setText(datas.get(position));
}
@Override
public int getItemCount() {//列表的长度
return datas.size();
}
}
这样就可以显示页面了
6、绘制分割线
(1)利用背景绘制
首先个MianActivity.xml文件中的RecyclerView添加背景颜色,为黑色
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:background="#000000"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
其次,在另一个xml文件中给布局文件添加背景设为黑色,且外边距设为1dp
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:background="#FFFFFF"
>
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#000000"
android:textSize="20sp" />
</RelativeLayout>
效果如图,原因在于,我们先设置大背景为黑色,再设置每个组件的布局文件背景为白色,且相邻组件之间的距离为1dp,这样就可以简便的绘制分割线,但局限性较大,线性布局可以用,但网格布局就很难使用
,
(2)利用recyclerView.addItemDecoration()方法
此方法非常好用且功能强大
我们需要在MainActivity中添加如下代码,且在res目录下的values/dimens中添加
recyclerView.addItemDecoration(new MyDecoration());
class MyDecoration extends RecyclerView.ItemDecoration{
@Override
//outRect 用来接收设置的数据,view 是 item 的实例,parent 是 RecyclerView 的实例,state 保存有一些 RecyclerView 的状态
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);//类似实现padding的效果
//outRect.set()方法设置偏移的大小,其中的参数表示左上右下
outRect.set(0,0,0,getResources().getDimensionPixelOffset(R.dimen.divideHeight));
}
}
除了outRect.set()方法外,还可以使用outRect.bottom=1;这个方法,其中bottom也可以换成left,right,top
<dimen name="divideHeight">1dp</dimen>
实现的效果与上图相同
其中getItemOffsets方法实现的功能类似于padding
(三)自定义分割线
recyclerView.addItemDecoration(new MyDecoration(this,R.drawable.shape));
class MyDecoration extends RecyclerView.ItemDecoration{
private Drawable drawable;//drawable是资源文件,自己设定的shape
public MyDecoration(Context context,int id){
drawable=context.getResources().getDrawable(id);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left=parent.getPaddingLeft();//返回左边距,之所以返回的是边距就是怕左右两边可能会存在滚动条,以免重合
int right=parent.getWidth()-parent.getPaddingRight();//返回的是宽度-右边距
int count=parent.getChildCount();//返回一个组中子元素个数的整数
for(int i=0;i<count;i++){
View view=parent.getChildAt(i);//item的实例
int top=view.getBottom();//每个实例的底部
int bottom=top+drawable.getIntrinsicHeight();
drawable.setBounds(left, top, right, bottom);
drawable.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0,0,0,drawable.getIntrinsicWidth());
}
}
shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient
android:centerColor="#00FF00"
android:startColor="#FF0000"
android:endColor="#0000FF"
android:type="linear"
/>
<size android:height="1dp" android:width="1dp"/>
</shape>
之前我们介绍过shape属性,这次用到了其中的gradient属性,也就是渐变色
7、格式的互换
在上图中可以看到,每一个itme的内容可以随之更改,这里以后再实际应用中还有更多,这里就拿一个较为简单的案例来实现
首先,再写一个holder和新的xml布局文件,再onCreateViewHolder中我们可以看到有一个int viewType,这个参数是可以通过不同的值展现不同的itemview,通过getItemViewType()方法进行重写,规定指定的位置若为偶数行返回0,奇数行返回1,此时在方法onCreateViewHolder()下进行判断,根据0或1,构建布局文件,结果如上图所示
class LinearViewHolder2 extends RecyclerView.ViewHolder{
private TextView textView;
private ImageView imageView;
public LinearViewHolder2(View itemView) {
super(itemView);
textView= (TextView) itemView.findViewById(R.id.tv);
imageView= (ImageView) itemView.findViewById(R.id.iv);
}
}
public int getItemViewType(int position) {//position指的是位置,也就是布局文件中每一行的索引,规定从第0行开始,下面的代码表示偶数行返回0,奇数行返回1
if(position %2==0){
return 0;
}else{
return 1;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {//可以通过不同的个viewType展现不同的itemView
if(viewType==0){
return new LinearViewHolder(layoutInflater.inflate(R.layout.content_main,parent,false));
}else{
return new LinearViewHolder2(layoutInflater.inflate(R.layout.content_main2,parent,false));
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if(getItemViewType(position)==0){
((LinearViewHolder)holder).textView.setText(datas.get(position));
}else {
((LinearViewHolder2)holder).textView.setText(datas.get(position));
}
}
8、点击事件
首先在Adapter.java文件下添加一个接口,之后在onBindViewHolder中添加一个事件监听器
private OnItemClickListener mlistener;
public LinearAdapter(Context context,List<String> data,OnItemClickListener listener){
this.datas=data;
this.contexts=context;
layoutInflater=layoutInflater.from(contexts);
this.mlistener=listener;
}
public interface OnItemClickListener{//定义一个接口,回调方法为了在MainActivity中直接使用OnClick()方法
void onClick(int pos);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if(getItemViewType(position)==0){
((LinearViewHolder)holder).textView.setText(datas.get(position));
}else {
((LinearViewHolder2)holder).textView.setText(datas.get(position));
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(contexts, "click:" + position, Toast.LENGTH_SHORT).show();
mlistener.onClick(position);
}
});
}
在MainAvtivity中将setAdapter方法进行修改,这样无论选择哪一个都会显示,不用在每个holder中都定义一个事件监听器
recyclerView.setAdapter(new LinearAdapter(this, data, new LinearAdapter.OnItemClickListener() {
@Override
public void onClick(int pos) {
Toast.makeText(MainActivity.this, "click:"+pos, Toast.LENGTH_SHORT).show();
}
}));
以上就是RecyclerView实现列表的操作,至于网格以及瀑布流,其实也很简单,如下代码,只需将setLayoutManger里面的内容进行修改即可
recyclerView.setLayoutManager(new GridLayoutManager(this,3));//3表示列数
//第一个参数根据第二个参数的结构有关,如果是垂直结构vertical则3表示3列,我这里是水平结构,3表示3行
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));
四、总结
RecyclerView的确功能很强大,理清整个逻辑其实并不是很难,需要花点时间去琢磨一下,如果还有其他的问题,今后遇到会做添加。