RecyclerView
本文参考郭霖《第一行代码》第2版
Recycyler不仅可以轻松实现和ListView同样的效果,还优化了ListView中存在的各种不足之处(性能不好,扩展性差,只能纵向滚动)。目前Android官方更加推荐使用RecyclerView,未来也会有更多的程序逐渐从ListView转向RecyclerView。
依赖库
RecyclerView定义在support库中,需要在项目module的build.gradle中添加相应的依赖库:
com.android.support:recyclerview-v7:25.0.1
app/build.gradle
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile project(':libzxing')
compile files('libs/volley.jar')
compile project(':slibrary')
compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.android.support:design:25.0.1'
compile 'com.android.support:support-v13:25.0.1'
compile 'com.android.support:support-v4:25.0.1'
compile files('libs/jackson/jackson-annotations-2.8.0.jar')
compile files('libs/jackson/jackson-core-2.8.1.jar')
compile files('libs/jackson/jackson-databind-2.8.1.jar')
compile 'com.android.support:recyclerview-v7:25.0.1'
}
RecycleView实现ListView的功能
- 新建一个Java Bean类Christmas.java,作为Adapter的适配类型。
package com.silion.androidproject.recycleview;
/**
* Created by silion on 2016/12/29.
*/
public class Christmas {
private String mName; //名字
private int mImageId; //图片ID
public Christmas(String name, int imageId) {
mName = name;
mImageId = imageId;
}
public String getName() {
return mName;
}
public void setName(String name) {
mName = name;
}
public int getImageId() {
return mImageId;
}
public void setImageId(int imageId) {
mImageId = imageId;
}
@Override
public String toString() {
return "Christmas{" +
"mName='" + mName + '\'' +
", mImageId=" + mImageId +
'}';
}
}
- 在layout目录新建Item的布局listitem_christmas_vertical.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="5dp"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/iconImageView"
android:layout_width="40dp"
android:layout_height="40dp"
tools:src="@drawable/christmas_santa"/>
<TextView
android:id="@+id/titleTextView"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="22sp"
tools:text="圣诞老人"/>
</LinearLayout>
- 新建自定义的ChristmasVerticalAdapter,这个Adapter继承于RecyclerView.Adapter,主要有4个点:
- 新建一个内部类ViewHolder继承于RecyclerView.ViewHolder,并作为Adapter的泛型类型。主要是用来缓存View,减少findViewById的开销
- 重写getItemCount()方法,RecyclerView Item的数量,直接返回数据list的size
- 重写onCreateViewHolder()方法,在这个方法中将listitem_christmas_vertical布局inflate进来,并且作为参数创建ViewHolder,创建的ViewHolder会自动实现之后重用,也就是说并不是所有的item都需要创建ViewHolder,点击事件一般也是在这里注册
- 重写onBindViewHolder()方法,该方法用于对RecyclerView item的数据进行赋值,会在每个item被滚动到屏幕内的时候执行
package com.silion.androidproject.recycleview;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.silion.androidproject.R;
import java.util.List;
/**
* Created by silion on 2016/12/29.
*/
public class ChristmasVerticalAdapter extends RecyclerView.Adapter<ChristmasVerticalAdapter.ViewHolder> {
List<Christmas> mChristmasList;
public ChristmasVerticalAdapter(List<Christmas> christmasList) {
mChristmasList = christmasList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_christmas_vertical, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Christmas christmas = mChristmasList.get(position);
holder.mIconImageView.setImageResource(christmas.getImageId());
holder.mTitleTextView.setText(christmas.getName());
}
@Override
public int getItemCount() {
return mChristmasList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView mIconImageView;
public TextView mTitleTextView;
public ViewHolder(View itemView) {
super(itemView);
mIconImageView = (ImageView) itemView.findViewById(R.id.iconImageView);
mTitleTextView = (TextView) itemView.findViewById(R.id.titleTextView);
}
}
}
- 在布局中加入RecyclerView,和加入ListView类似,但RecyclerView并不是内置在系统SDK中,所以需要把完整的包路径写出来。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
在代码中使用RecyclerView,必选的有5点
- 通过findViewById获取在布局中添加的RecyclerView实例
- 新建Adapter实例,数据list作为构造方法的参数
- 新建LayoutManager实例,这里使用LinearLayoutManager,默认方向是vertical
- 给RecyclerView设置LayoutManager
- 给RecyclerView设置Adapter
默认的RecyclerView是没有像ListView那样的分割线的,如果需要,可以通过继承RecyclerView.ItemDecoration实现自定义的分割线。
在v7:25.0.1的RecyclerView包Android也已经给我们实现了和ListView的divider一样效果的分割线DividerItemDecoration。
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
mChristmasAdapter = new ChristmasVerticalAdapter(((RecyclerViewActivity) getActivity()).getChristmas());
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mChristmasAdapter);
// 在v7:25.0.1的RecyclerView包Android实现的DividerItemDecoration
DividerItemDecoration decoration = new DividerItemDecoration(mContext, LinearLayoutManager.VERTICAL);
// 默认是android.R.attr.listDivier样式,可以通过setDrawable设置自定义的divider样式
decoration.setDrawable(mContext.getDrawable(R.drawable.recycler_view_divider));
mRecyclerView.addItemDecoration(decoration);
效果图
RecycleView实现横向滚动功能
新建一个Java Bean类Christmas.java,作为Adapter的适配类型。
在layout目录新建Item的布局listitem_christmas_horizontal.xml,因为是横向滚动,所以把Item的布局改成纵向
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="100dp"
android:padding="5dp"
android:layout_height="100dp">
<ImageView
android:id="@+id/iconImageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
tools:src="@drawable/christmas_santa"/>
<TextView
android:id="@+id/titleTextView"
android:layout_marginTop="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="22sp"
tools:text="圣诞老人"/>
</LinearLayout>
- 新建自定义的ChristmasHorizontalAdapter,这个Adapter继承于RecyclerView.Adapter,在onCreateViewHolder方法将listitem_christmas_horizontal布局inflate进来作为构造方法创建ViewHolder实例
@Override
public ChristmasHorizontalAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_christmas_horizontal, parent, false);
ChristmasHorizontalAdapter.ViewHolder viewHolder = new ChristmasHorizontalAdapter.ViewHolder(view);
return viewHolder;
}
在布局中加入RecyclerView
在代码中使用RecyclerView,LayoutManager还是用LinearLayoutManager,但是设置方向为横向,divider使用listview默认的样式
RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
ChristmasHorizontalAdapter christmasAdapter = new ChristmasHorizontalAdapter(((RecyclerViewActivity) getActivity()).getChristmas());
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager); // 设置为横向
recyclerView.addItemDecoration(new DividerItemDecoration(mContext, LinearLayoutManager.HORIZONTAL));
recyclerView.setAdapter(christmasAdapter);
效果图
RecycleView实现瀑布流布局
新建一个Java Bean类Christmas.java,作为Adapter的适配类型。
在layout目录新建Item的布局listitem_christmas_staggered_grid.xml,这里使用RelativeLayout包住LinearLayout将图片和标题放在中间
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<ImageView
android:id="@+id/iconImageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
tools:src="@drawable/christmas_santa"/>
<TextView
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp"
android:textSize="22sp"
tools:text="圣诞老人"/>
</LinearLayout>
</RelativeLayout>
- 新建自定义的ChristmasHorizontalAdapter,这个Adapter继承于RecyclerView.Adapter
1.在onCreateViewHolder方法将listitem_christmas_staggered_grid布局inflate进来作为构造方法创建ViewHolder实例,并注册点击事件监听
2.瀑布流布局需要各个Item的高度不一致才能看的出效果,所以将每个Item的高度设为随机值
@Override
public ChristmasStaggeredGridApdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_christmas_staggered_grid, parent, false);
StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
params.height = getRandomHeight(); //高度设为随机值
final ChristmasStaggeredGridApdapter.ViewHolder viewHolder = new ChristmasStaggeredGridApdapter.ViewHolder(view);
// 给Item设置点击事件监听
viewHolder.mItemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = viewHolder.getAdapterPosition();
Christmas christmas = mChristmasList.get(position);
Toast.makeText(view.getContext(), "点击了" + christmas.getName() + "Item", Toast.LENGTH_SHORT).show();
}
});
// 给Icon设置点击事件监听
viewHolder.mIconImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = viewHolder.getAdapterPosition();
Christmas christmas = mChristmasList.get(position);
Toast.makeText(view.getContext(), "点击了" + christmas.getName() + "Iamge", Toast.LENGTH_SHORT).show();
}
});
return viewHolder;
}
在布局中加入RecyclerView
在代码中使用RecyclerView
1.LayoutManager使用StaggeredGridLayoutManager,构造函数接收2个参数,第一个参数用于指定布局的列数,第二个参数用于指定布局的排列方向
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_recycler_view, container, false);
RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
ChristmasStaggeredGridApdapter christmasAdapter = new ChristmasStaggeredGridApdapter(((RecyclerViewActivity) getActivity()).getChristmas());
recyclerView.setAdapter(christmasAdapter);
return rootView;
}
效果图