RecycleView已经面世很久,相信大家也已经有所熟悉,也在很多应用中得到广泛的使用。那么RecyclerView拥有比ListView,GridView之类控件都有哪些优点呢:
RecycleView的简单介绍:
有关recycleview的介绍,网上已经有了好多,在次小白理解尚浅,就不过多介绍了
①.采用LayoutManager来处理Item的布局
②.提供Item操作的默认动画,例如在增加或者删除item的时候
你也可以自定义LayoutManager或者设置添加/删除的动画,整体的RecyclerView结构图如下:
RecyclerView提供了三种内置的LayoutManager:
* LinearLayoutManager:线性布局,横向或者纵向滑动列表
线性布局,类型包括Vertical和Horizontal
GridLayoutManager:表格布局,继承自LinearLayoutManager,实现效果类似GridView
* StaggeredGridLayoutManager:流式布局,例如瀑布流效果交错的格子布局,同样也是LayoutManager的实现类,类型包括Vertical和Horizontal,与GridLayoutManager很相似,不过是交错的格子,也就是宽高不等的格子视图,类似瀑布流的效果
RecycleView的基本用法:
compile 'com.android.support:design:23.1.1'
(这个包下也有) 或者 compile'com.android.support:recyclerview-v7:23.1.1’
1、RecycleView的适配器Adapter:适配器,绑定数据集
继承 RecyclerView.Adapter
要重写的方法
// 创建ViewHolder ,相当于ListVie Adapter 的getView 方法
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return null;
}
// 数据绑定
public void onBindViewHolder(ViewHolder viewHolder, int i) {}
// 数据的长度
public int getItemCount() { return 0;}
2、ViewHolder:根据当前的数据保存视图
继承 RecyclerView.ViewHolder
要重写的方法
class ViewHolder extends RecyclerView.ViewHolder{
public ViewHolder(View itemView) {
super(itemView);
// 绑定控件
}
}
3、ItemDecoration:勉强理解为item装饰器,可以美化item
1.继承 RecyclerView.ItemDecoration
2. 重要方法:
//在itemView绘制完成之前调用,也就是说此方法draw出来的效果将会在itemView的下面
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
{
super.onDraw(c, parent, state);
}
//与onDraw相反,draw出来的效果将叠加在itemView的上面
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
{
super.onDrawOver(c, parent, state);
}
//算通过配置outRect来设置itemView的inset边界,相当于设置itemView的margin
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
}
4、ItemAnimator:动画(当item被增加,删除,重新摆放时动画才有效)。
1.继承 RecyclerView.ItemAnimator
2. 提供默认的Animator:DefaultItemAnimator
3.github 开源
https://github.com/gabrielemariotti/RecyclerViewItemAnimators
5、LayoutManager:布局管理器。决定item如何摆放
LinearLayoutManager
线性布局,LayoutManager的实现类,类型包括Vertical和Horizontal
GridLayoutManager
格子布局,继承自LinearLayoutManager,实现效果类似GridView
StaggeredGridLayoutManager
交错的格子布局,同样也是LayoutManager的实现类,类型包括Vertical和Horizontal,与GridLayoutManager很相似,不过是交错的格子,也就是宽高不等的格子视图,类似瀑布流的效果
MainActivity.java
package com.example.recycleviewdemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
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 MainActivity extends AppCompatActivity {
/**
* 数据集合
*/
private List mDatas;
//控件
private RecyclerView mRecyclerView;
//适配器
private MyAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDatas = new ArrayList<>();
ininViews();
initData();
initAdapter();
}
//初始化布局控件
private void ininViews() {
mRecyclerView = (RecyclerView) findViewById(R.id.recycleview);
}
private void initAdapter() {
//初始化adapter
mAdapter = new MyAdapter(mDatas);
/**
* Support库提供了两个现成的子类:LinearLayoutManager和StaggeredGridLayoutManager。
* 前者可以获得和ListView一样的布局,还可以是水平方向的;后者则提供了形如GridView的布局。
*/
mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
//设置adapter
mRecyclerView.setAdapter(mAdapter);
//画横线
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
//默认动画 貌似官方就提供了这一种默认的动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
/**
* 在这我们就能实现item的点击事件了
*/
mAdapter.setListener(new MyAdapter.OnItemClickListener() {
@Override
public void onClick(View v, int position, String str) {
Toast.makeText(MainActivity.this, "点击我干嘛啊,真是没事找事", Toast.LENGTH_SHORT).show();
}
});
}
/**
* 添加事件
*
* @param view
*/
public void btnAdd(View view){
mAdapter.addData("小红", 3);
}
/**
* 删除事件
*
* @param view
*/
public void btnDelete(View view){
mAdapter.remove(4);
}
/**
* 初始化集合数据
*/
private void initData() {
mDatas.add("New York");
mDatas.add("Bei Jing");
mDatas.add("Boston");
mDatas.add("London");
mDatas.add("San Francisco");
mDatas.add("Chicago");
mDatas.add("Shang Hai");
mDatas.add("Tian Jin");
mDatas.add("Zheng Zhou");
mDatas.add("Hang Zhou");
mDatas.add("Guang Zhou");
mDatas.add("Fu Gou");
mDatas.add("Zhou Kou");
}
}
MyAdapter.java:
package com.example.recycleviewdemo;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
/**
* Created by 若兰 on 2016/1/27.
* 一个懂得了编程乐趣的小白,希望自己
* 能够在这个道路上走的很远,也希望自己学习到的
* 知识可以帮助更多的人,分享就是学习的一种乐趣
* QQ:1069584784
* csdn:http://blog.csdn.net/wuyinlei
*/
/**
* Adapters provide a binding from an app-specific data
* set to views that are displayed within a RecyclerView.
*/
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private LayoutInflater mInflater;
private List mLists;
private OnItemClickListener mListener;
public void setListener(OnItemClickListener listener) {
mListener = listener;
}
public MyAdapter(List lists) {
mLists = lists;
}
//创建布局
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mInflater = LayoutInflater.from(parent.getContext());
//加载布局
View view = mInflater.inflate(R.layout.item_recycle, null);
//返回viewholder
return new MyViewHolder(view);
}
/**
* 在指定的位置添加数据
*
* @param data
* @param position
*/
public void addData(String data, int position) {
mLists.add(data);
//通知布局在那个地方插入的数据
notifyItemInserted(position);
}
/**
* 移除特定的位置的数据
*
* @param position 索引位置
*/
public void remove(int position) {
mLists.remove(position);
notifyItemRemoved(position);
}
public void addData(List datas) {
mLists.addAll(datas);
//通知添加数据,第一个位置 数据的数量
notifyItemRangeChanged(0, datas.size());
}
//绑定布局
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.mTextView.setText(mLists.get(position));
}
//获取到item的个数
@Override
public int getItemCount() {
return mLists.size();
}
// 强制使用ViewHolder
/**
* 在ListView性能优化方面,Android就推荐使用ViewHolder来减少findViewById()的使用以提高效率。
* 不过对于ListView上的ViewHolder,Android只是建议而非强制使用。不过因为使用ViewHolder
* 模式太有意义了,所以在RecyclerView中ViewHolder就变成了必须使用的模式,Adapter要求返回的也
* 从普通的View变成了ViewHolder。
* 不过如果实现时没有自定义的一些View实际变量,ViewHolder也依然失去其意义。
*/
class MyViewHolder extends RecyclerView.ViewHolder {
private TextView mTextView;
public MyViewHolder(View itemView) {
super(itemView);
if (itemView != null) {
mTextView = (TextView) itemView.findViewById(R.id.textview);
mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null) {
/**
* getLayoutPosition() 返回的是item的当前点击的位置
* Returns the position of the ViewHolder in terms of the latest layout pass.
*/
mListener.onClick(v, getLayoutPosition(), mLists.get(getLayoutPosition()));
}
}
});
}
}
}
/**
* 没有OnItemClickListener
* 必须我们自己去实现
*/
interface OnItemClickListener {
void onClick(View v, int position, String str);
}
}
DividerItemDecoration.java:(绘制item之间的直线的,本身没有提供,要自己写)
package com.example.recycleviewdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by 若兰 on 2016/1/26.
* 一个懂得了编程乐趣的小白,希望自己
* 能够在这个道路上走的很远,也希望自己学习到的
* 知识可以帮助更多的人,分享就是学习的一种乐趣
* QQ:1069584784
* csdn:http://blog.csdn.net/wuyinlei
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
/**
* 采用系统的内置的分割线风格
*/
private static final int[] attrs = new int[]{android.R.attr.listDivider};
private final TypedArray mTypedArray;
//水平方式
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
//垂直方式
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
//方向
private int mOrientation;
/**
* 默认方向是垂直的
*/
public DividerItemDecoration(Context context, int orientation) {
super();
//读取系统自定义属性
// Returns a TypedArray holding an array of the attribute values.
mTypedArray = context.obtainStyledAttributes(attrs);
mDivider = mTypedArray.getDrawable(0);
//回收资源
mTypedArray.recycle();
setHorizontal(orientation);
}
/**
* 判断传入的是横向的还是纵向的
*
* @param orientation
*/
private void setHorizontal(int orientation) {
//如果两种都不是就抛出异常
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("错误的方式");
}
mOrientation = orientation;
}
//left top right bottom
/**
* 绘制 根据传入的是水平的还是垂直的
*
* @param c
* @param parent
* @param state
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
/**
* linear 垂直列表
*
* @param c
* @param parent
*/
private void drawVertical(Canvas c, RecyclerView parent) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
//得到布局中的子item
View childView = parent.getChildAt(i);
//得到子view的布局泵 LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams();
/**
* top 是子view的底布局加上和他的底margin值
*/
int top = childView.getBottom() + layoutParams.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
//设置四个方向的bounds
mDivider.setBounds(left, top, right, bottom);
//然后画线
mDivider.draw(c);
}
}
/**
* 横向列表的横线
*
* @param c
* @param parent
*/
private void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
activity_main.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<Button
android:layout_weight="1"
android:onClick="btnAdd"
android:text="添加"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:text="删除"
android:onClick="btnDelete"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycleview"
android:layout_width="match_parent"
android:layout_height="match_parent">
android.support.v7.widget.RecyclerView>
LinearLayout>
item_recycle.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textview"
android:gravity="center"
android:text="hello"
android:textSize="20dp"
android:padding="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
RelativeLayout>
好了,基本上这些应该可以满足工作中的的一般事情了,(或许是我自大了哈),RecycleView的知识好多呢,这个要想了解一手的资料,建议还是去官方去看下。
如果有兴趣可以看下我的另一篇文章,RecycleView+SwipeRefreshLayout实现下拉刷新和 RecycleView+MaterialRefreshLayout实现下拉刷新和上拉加载更多。希望有所帮助
RecycleView + SwipeRefreshLayout 实现下拉刷新:
MaterialRefreshLayout实现下拉刷新上拉加载更多: