您的位置:首页 > 其它

初探RecyclerView开发

2016-12-08 15:24 162 查看
很长时间没有从事android项目开发了,最近一直在看android新的知识,android开发中列表是非常常见的,以前LIstView效果比较单一,扩展多了会影响性能,现在比较火的RecyclerVIew引起了我的兴趣,决定学习一下。很久没写博客了,顺便记录下,以便回顾。

1,RecyclerView简介

RecyclerView是从android5.0版本开始推出的,依赖于support-v7的一款新的组件,功能强大,不仅可以实现原来ListView的线性列表的效果,还可以实现GridView的网格列表效果以及瀑布流的效果,可以分别通过LinearLayoutManager,GridLayoutManager,StaggeredGridLayoutManager来管理横向或者竖向的滑动效果。通过自定义继承ItemDecoration类来实现分割线的绘制和效果。Adapter里面封装了复用逻辑,返回的是ViewHolder,不是View。另外还添加了可以控制item增删的动态动画效果。

2,入门实践

废话不多说,开始实践。

1)布局

理所当然,打开布局文件,先布局一个RecyclerView控件进去(这里有部分童鞋会发现怎么自动补全里面没有RecyclerView,或者打上去报错,解决方法:在app目录下面的build.gradle文件里面,在“compile 'com.android.support:appcompat-v7:xx.x.x'”下面加一行代码“compile
'com.android.support:recyclerview-v7:xx.x.x'”,然后clean一下project,这个时候就有RecyclerView控件了),设置好宽高铺满。

2)查找组件

在Activity中查找组件,设置属性:

//查找控件
recyclerview = (RecyclerView) findViewById(R.id.recyclerview);
//创建设置布局管理器
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerview.setLayoutManager(layoutManager);


LinearLayoutManager设置是横向还是竖向滑动。

3)自定义适配器

自定义适配器,需要继承Adapter类,面向ViewHolder,但是需要自己定义ViewHolder类。

同时需要实现三个方法:

getItemCount()

这个方法就是返回获得数据的数目。

onCreateViewHolder()

生成每个item的view,封装到ViewHolder里面去,返回ViewHolder。

onBindViewHolder()

适配数据到view中去。

贴上代码:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {

private Context mContext;
private List<String> data;

public RecyclerAdapter(Context context, List<String> d){
mContext = context;
data = d;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = LayoutInflater.from(mContext).inflate(R.layout.item_lay,parent,false);
MyViewHolder vh = new MyViewHolder(view);

return vh;
}

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.tv.setText(data.get(position).toString());

}

@Override
public int getItemCount() {
return data.size();
}

class MyViewHolder extends RecyclerView.ViewHolder {

public TextView tv;

public MyViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.tv);
}
}

}
顺便附上item布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="50dp"
>

<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:textColor="#ffffff"
android:background="#999999" />

</LinearLayout>


此时需要在Activity中实例化适配器,绑定适配器到REcyclerView了:

private RecyclerAdapter adapter;
//绑定适配器
adapter = new RecyclerAdapter(this,mData);
在这之前记得初始化添加数据集:

private List<String> mData;
mData = new ArrayList<String>();
for(int i = 0;i < 20;i++){
mData.add("第"+i+"行");
}


此时运行,就会看到无分割线的列表。

4)自定义分割线
RecyclerView的分割线不像ListView的分割线那样直接配置属性就好了,这里稍微繁琐一点,需要自定义继承ItemDecoration类。

主要要重写三个方法:getItemOffsets(),还有onDraw()和onDrawOver两者其中之一就可以了。

getItemOffsets()

从字面意思就是Item要偏移, 由于我们在Item和Item之间加入了分隔线,线其实本质就是一个长方形,也是用户自定义的,既然线也有长宽高,就画横线来说,上面的Item加入了分隔线,那下面的Item就要往下平移,平移的量就是分隔线的高度。

这里面重要的是要拿到画分割线的坐标,也就是left,top,right,bottom的值。

①首先讲一下忽略item布局里面设置的margin,padding属性,来获取坐标值。

a)竖向的列表,即横向绘制分割线
left:0
right:parent.getWidth()
top:每个item的底部,就是下面的分割线的top,可以通过childView.getBottom()来获取到。
bottom:就是top+想绘制的分割线的高度。
b)横向列表,即竖向绘制分割线
top:0
bottom:parent.getHeight()
left:每个item的右边,就是后面分割线的left,可以通过childView.getRight()来获取到
right:就是left+分割线的宽度
②再来讲下考虑padding,margin属性的获取方法

a)竖向的列表,即横向绘制分割线
left:0+parent.getPaddingLeft()
right:parent.getWidth() - parent.getPaddingRight
top:每个item的底部+底部margin的值,就是下面的分割线的top,可以通过childView.getBottom()来获取到,再加上view的LayoutParams调用bottomMargin。
bottom:就是top+想绘制的分割线的高度。
b)横向列表,即竖向绘制分割线
top:0+parent.getPaddingTop()
bottom:parent.getHeight() - parent.getPaddingBottom()
left:每个item的右边+右边的margin,就是后面分割线的left,可以通过childView.getRight()来获取到,再加上view的LayoutParams调用rightMargin
right:就是left+分割线的宽度
直接上代码:

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

private Context mContext;
private Drawable divider;
private int mOrientation;
private static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
private static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

public static final int [] ATTRS = new int[]{
android.R.attr.listDivider
};

public DividerItemDecoration(Context context,int orientation){
super();
mContext = context;
mOrientation = orientation;
TypedArray ta = context.obtainStyledAttributes(ATTRS);
this.divider = ta.getDrawable(0);
ta.recycle();
setOrientation(orientation);
}

//设置屏幕方向
private void setOrientation(int orientation){
if(orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST){
throw new IllegalArgumentException("invalid orientation");
}
}

//画横线
public void drawHorizontalLine(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);
//获取childView的布局信息
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
int top = view.getBottom() + params.bottomMargin;
int bottom = top+divider.getIntrinsicHeight();
divider.setBounds(left,top,right,bottom);
divider.draw(c);
}
}

//画竖线
public void drawVerticalLine(Canvas c, RecyclerView parent,RecyclerView.State state){
int top = parent.getPaddingTop();
int bottom = parent.getHeight() - parent.getPaddingBottom();
int count = parent.getChildCount();
for(int i = 0;i < count;i++){
View view = parent.getChildAt(i);
//获取childview布局信息
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
int left = view.getRight() + params.rightMargin;
int right = left + divider.getIntrinsicWidth();
divider.setBounds(left,top,right,bottom);
divider.draw(c);
}
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if(mOrientation == HORIZONTAL_LIST){
//画横线,就是往下偏移一个分割线的高度
outRect.set(0, 0, 0, divider.getIntrinsicHeight());
}else {
//画竖线,就是往右偏移一个分割线的宽度
outRect.set(0, 0, divider.getIntrinsicWidth(), 0);
}
}

@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
if(mOrientation == VERTICAL_LIST){
drawHorizontalLine(c,parent,state);
}else{
drawVerticalLine(c,parent,state);
}
}
}


附上分割线代码:

drawable:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#7b7a7a"/>
<size android:height="1dp"/>
</shape>


在AppTheme下添加

<item name="android:listDivider">@drawable/divider</item>
然后在Activity中给RecyclerVIew添加分割线:

//添加自定义分割线
recyclerview.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));


此时运行,就会发现item下面有华丽丽的分割线了。

5)实现item点击事件
RecyclerView不像ListView有onItemClickListener事件,这里需要自己在Adapter中添加点击事件的监听。

//item回调接口
public interface OnItemClickListener{
void OnItemClick(View view,int position);
}
创建一个对外开放的事件调用:

//开放的点击监听器的方法
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
mOnItemClickListener = onItemClickListener;
}


不多说了,再上一次Adapter的代码。
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {

private Context mContext;
private List<String> data;
private OnItemClickListener mOnItemClickListener;

public RecyclerAdapter(Context context, List<String> d){
mContext = context;
data = d;
}

//item回调接口 public interface OnItemClickListener{ void OnItemClick(View view,int position); }

//开放的点击监听器的方法 public void setOnItemClickListener(OnItemClickListener onItemClickListener){ mOnItemClickListener = onItemClickListener; }

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = LayoutInflater.from(mContext).inflate(R.layout.item_lay,parent,false);
MyViewHolder vh = new MyViewHolder(view);

return vh;
}

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.tv.setText(data.get(position).toString());
if(mOnItemClickListener != null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnItemClickListener.OnItemClick(holder.itemView,position);
}
});
}
}

@Override
public int getItemCount() {
return data.size();
}

class MyViewHolder extends RecyclerView.ViewHolder {

public TextView tv;

public MyViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.tv);
}
}

}


在Activity中添加:

adapter.setOnItemClickListener(new RecyclerAdapter.OnItemClickListener() {
@Override
public void OnItemClick(View view, int position) {
Toast.makeText(MainActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show();
}
});


源码地址:http://download.csdn.net/detail/liujibin1836591303/9705656
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: