Android开发中RecyclerView组件使用的一些进阶技讲解

RecyclerView的优势:

它自带ViewHolder来实现View的复用机制,再也不用ListView那样在getView()里自己写了 使用LayoutManager可以实现ListView,GridView以及流式布局的列表效果 通过setItemAnimator(ItemAnimator animator)可以实现增删动画(懒的话,可以使用默认的ItemAnimator对象,效果也不错) 控制item的间隔,可以使用addItemDecoration(ItemDecoration decor),不过里边的ItemDecoration是一个抽象类,需要自己去实现...

用法介绍:

导入RecyclerView的v7库:
RecyclerView是一个android.support.v7库里的控件,因此在使用的时候我们需要在gradle配置文件里加上compile 'com.android.support:recyclerview-v7:22.2.1'来引入google官方的这个库
xml布局中,使用常规的控件引入方式,来引入RecyclerView,如下:

<android.support.v7.widget.RecyclerView android:id="@+id/recyclerview_content" style="?recyclerview_style" android:scrollbars="vertical" android:fadeScrollbars="true" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="-55dp" />

代码中的写法基本和ListView相差无几,但还是要重点说一下:

在实例化RecyclerView之后,我们需要使用setLayoutManager()给它设置布局管理器,其中的实参即就是LayoutManager,这里总共有两种LayoutManager:

1.StaggeredGridLayoutManager,是我们之前提到的流式布局:
它有一个构造方法StaggeredGridLayoutManager(int spanCount, int orientation),第一个是网格的列数,第二个参数是数据呈现的方向
(如果是竖直,那么第一个参数的意义就是列数,反之为行数。而且第二个参数在StaggeredGridLayoutManager里也有同样名称的常量,请同学们自行采纳[这里还是建议大家使用库里自带的常量,因为他们一般都是整型值,这样可以避免各个类里所判别的常量值不一样而导致的其他问题]);
2.GridLayoutManager,网格布局(流式布局应该是它的一个特殊情况):
GridLayoutManager(Context context, int spanCount)或
GridLayoutManager(Context context, int spanCount, int orientation,
 boolean reverseLayout)需要说明的是,最后一个参数表示的是是否逆向布局(意思是将数据反向显示,原先从左向右,从上至下。设为true之后全部逆转)。
小提示:在这两个LayoutManager中,默认的orientation为vertical,reverseLayout为false。对应的参数在GridLayoutManager中都有对应的方法来进行补充设置。而在StaggeredGridLayoutManager中所有的方法都针对reverseLayout做了判断,然而它并没有给出这个参数设定值的api。

线性布局, LinearLayoutManager
LinearLayoutManager(Context context)构建一个默认布局方向为VERTICAL的RecyclerView,这种样式也是ListView默认的。
LinearLayoutManager(Context context, int orientation, boolean reverseLayout)。发现没有,线性布局和网格布局几乎是一样的。只是少了一个spanCount参数。

和ListView一样,为RecyclerView设置Adapter

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> { @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MyViewHolder holder = new MyViewHolder(LayoutInflater.from( HomeActivity.this).inflate(R.layout.item_home, parent, false)); return holder; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.tv.setText(mDatas.get(position)); } @Override public int getItemCount() { return mDatas.size(); } class MyViewHolder extends ViewHolder { TextView tv; public MyViewHolder(View view) { super(view); tv = (TextView) view.findViewById(R.id.id_num); } } }

如上,即就是Adapter的写法。其中的ViewHolder就是拿来负责View的回收和复用的,这样就不需要我们自己写完ViewHolder之后,还要在getView(int position, View convertView, ViewGroup parent)里一顿判断,一顿绑定,一顿find了。而且这里的ViewHolder成为了RecyclerView中必须继承的一部分,重写完后就需要放入 RecyclerView.Adapter< >这里来对基类的范型初始化。

在这里,Recyclerview已经为你封装好了:

getItemCount()就不必多说了,和ListView是一样的 getItemViewType(int position)是用来根据position的不同来实现RecyclerView中对不同布局的要求。从这个方法中所返回的值会在onCreateViewHolder中用到。比如头部,尾部,等等的特殊itemView(这里说成ViewHolder比较好)都可以在这里进行判断。 onCreateViewHolder(ViewGroup parent, int viewType)是用来配合写好的ViewHolder来返回一个ViewHolder对象。这里也涉及到了条目布局的加载。viewType则表示需要给当前position生成的是哪一种ViewHolder,这个参数也说明了RecyclerView对多类型ItemView的支持。 onBindViewHolder(MyViewHolder holder, int position)专门用来绑定ViewHolder里的控件和数据源中position位置的数据。

这里,会有人问,那么item的子控件findViewById 去哪儿了?我们把它交给了ViewHolder的构造方法(其他方法也可以),它的本质是在onCreateViewHolder方法里生成ViewHolder的时候执行的。

提升:
1.代码重构:
在上边看了这么多,有木有觉得,ViewHolder的功能并不是非常明确?它既负责了子控件的查询,又负责了子控件的装载工作。而布局加载和数据绑定却交给了Adapter......
我们来看看掘金的做法:
首先,它把Adapter和ViewHolder的功能以一种较为低耦合的方式进行了职能分离,让ViewHolder里所有的逻辑代码全部都只出现在ViewHolder中。我们现在就对前边提到的代码进行重构:

ViewHodler:

class MyViewHolder extends ViewHolder{ TextView tv; public MyViewHolder(Context context, View view){ super(view); tv = (TextView) view.findViewById(R.id.id_num); //当然,我们也可以在这里使用view来对RecyclerView的一个item进行事件监听,也可以使用 //tv等子控件来实现item的子控件的事件监听。这也是我之所以要传context的原因之一呢~ ...... } public static MyViewHolder newInstance(Activity context, ViewGroup parent){ View view = LayoutInflater.from( context).inflate(R.layout.item_home, parent,false); return new MyViewHolder(context, view); } } //你没看错,数据绑定也被整合进来了, //将adapter里的数据根据position获取到后传进来。当然,也可以根据具体情况来做调整。 public void onBinViewHolder(String data){ tv.setText(data);//既然这里也有子控件,那么这里也可以做item子控件的事件监听喽 }

RecyclerView:

class HomeAdapter extends RecyclerView.Adapter<MyViewHolder>{ @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){//如需要,还要对viewType做判断 return MyViewHolder.newInstance(this, parent) } @Override public void onBindViewHolder(MyViewHolder holder, int position){ holder.onBindViewHolder(mDatas.get(position)); } @Override public int getItemCount(){ return mDatas.size(); } }

抽取一个条目点击事件,让它更像ListView:

class HomeAdapter extends RecyclerView.Adapter<MyViewHolder>{ private OnItemClickListener mOnItemClickListener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){//如需要,还要对viewType做判断 return MyViewHolder.newInstance(this, parent) } @Override public void onBindViewHolder(MyViewHolder holder, int position){ holder.onBindViewHolder(mDatas.get(position)); //如果设置了回调,则设置点击事件 if (mOnItemClickLitener != null) { viewHolder.itemView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mOnItemClickLitener.onItemClick(viewHolder.itemView, i); } }); } } @Override public int getItemCount(){ return mDatas.size(); } public interface OnItemClickLitener { void onItemClick(View view, int position); } }

接口调用

mAdapter.setOnItemClickLitener(new OnItemClickLitener() { @Override public void onItemClick(View view, int position) { ...... } });

2.External
上边提到了

控制item的间隔,可以使用addItemDecoration(ItemDecoration decor),不过里边的ItemDecoration是一个抽象类,需要自己去实现...
这个问题,那我们来实际解决一下:

这是羊神实现的一个子类

package com.zhy.sample.demo_recyclerview; 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.support.v7.widget.RecyclerView.State; import android.util.Log; import android.view.View; public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; 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) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDraw(Canvas c, RecyclerView parent) { Log.v("recyclerview - itemdecoration", "onDraw()"); if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext()); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public 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, int itemPosition, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } }

然后就是为我们的RecyclerView实例添加分割线

addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));

系统默认的分割线往往达不到我们产品和设计师的要求,怎么办呢?

<item name="android:listDivider">@drawable/your_custom_divider</item>

通过以上xml属性,将系统的listDivider设为自己画出来的分割线,只需要放在你对应activity的主题下即可。

技巧:RecyclerView 滚动条的显示与隐藏

<android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" > </android.support.v7.widget.RecyclerView>

纵向显示:

android:scrollbars="vertical"

横向显示:

android:scrollbars="horizontal"

隐藏:

android:scrollbars="none"

时间: 2024-08-19 23:34:59

Android开发中RecyclerView组件使用的一些进阶技讲解的相关文章

Android开发中RecyclerView组件使用的一些进阶技讲解_Android

RecyclerView的优势: 它自带ViewHolder来实现View的复用机制,再也不用ListView那样在getView()里自己写了 使用LayoutManager可以实现ListView,GridView以及流式布局的列表效果 通过setItemAnimator(ItemAnimator animator)可以实现增删动画(懒的话,可以使用默认的ItemAnimator对象,效果也不错) 控制item的间隔,可以使用addItemDecoration(ItemDecoration

Android开发中RecyclerView模仿探探左右滑动布局功能

我在此基础上优化了部分代码, 添加了滑动回调, 可自定义性更强. 并且添加了点击按钮左右滑动的功能. 据说无图都不敢发文章了. 看图: 1:这种功能, 首先需要自己管理布局 继承 RecyclerView.LayoutManager , 显示自己管理布局, 比如最多显示4个view, 并且都是居中显示. 底部的View还需要进行缩放,平移操作. public class OverLayCardLayoutManager extends RecyclerView.LayoutManager { p

Android开发中RecyclerView控件使用实例教程

Android RecyclerView 是Android5.0推出来的,导入support-v7包即可使用. 个人体验来说,RecyclerView绝对是一款功能强大的控件. 首先总结下RecyclerView的特点: 1.支持不同方向,不同排版模式,实现多种展现数据的形式,涵盖了ListView,GridView,瀑布流等数据表现的形式 2.内部实现了回收机制,无需我们考虑View的复用情况 3.取消了onItemClick等点击事件,需要自己手动去写 -------------------

Android开发中重要组件activity 生命周期以及启动模式分析

Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务. Activity中所有操作都与用户密切相关,是一个负责与用户交互的组件,可以通过setContentView(View)来显示指定控件. 在一个android应用中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应.Activity之间通过Intent进行通信. Activity生命周期 安卓活动由一个返回栈管理 安卓活动有四个状态 1.运行状态 当一个活动位

android开发中重要组件Activity详细学习教程

Activity是Android组件中最基本也是最为常见用的四大组件(Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器)之一.它间接继承自android.content.Context,因此,有些时候都直接把Activity实例当做Context的实例来使用. 如前面所提到的要在应用程序中使用Activity,必须在Android Manifest.xml中配置它. 新建一个Android工程,新建过程中勾选creat

Android应用开发中RecyclerView组件使用入门教程_Android

RecyclerView是一种列表容器, 发布很久了, 才想起来写点什么. RecyclerView相比于ListView, 在回收重用时更具有灵活性, 也就是低耦合, 并且提供了扩展. 加载多个视图时, 应该多用RecyclerView代替ListView. 那么我们来看看这东西应该怎么用? 比如生成一个瀑布流的视图. 首先我们从一个HelloWorld写起, 看看如何构建一个RecyclerView. 1. 依赖库Gradle配置, 添加Recycler库 compile 'com.andr

Android应用开发中RecyclerView组件使用入门教程

RecyclerView是一种列表容器, 发布很久了, 才想起来写点什么. RecyclerView相比于ListView, 在回收重用时更具有灵活性, 也就是低耦合, 并且提供了扩展. 加载多个视图时, 应该多用RecyclerView代替ListView. 那么我们来看看这东西应该怎么用? 比如生成一个瀑布流的视图. 首先我们从一个HelloWorld写起, 看看如何构建一个RecyclerView. 1. 依赖库 Gradle配置, 添加Recycler库 compile 'com.and

Android开发中RecyclerView简单使用

那么有了ListView.GridView为什么还需要RecyclerView这样的控件呢?整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果. 你想要控制其显示的方式,请通过布局管理器LayoutManager 你想要控制Item间的间隔(可绘制),请通过ItemDecoration 你想要控制Item增删的动画,请通过ItemAnim

Android开发中编写蓝牙相关功能的核心代码讲解_Android

一. 什么是蓝牙(Bluetooth)?1.1  BuleTooth是目前使用最广泛的无线通信协议 1.2  主要针对短距离设备通讯(10m) 1.3  常用于连接耳机,鼠标和移动通讯设备等.二. 与蓝牙相关的API2.1 BluetoothAdapter: 代表了本地的蓝牙适配器 2.2 BluetoothDevice 代表了一个远程的Bluetooth设备三. 扫描已经配对的蓝牙设备(1)注:必须部署在真实手机上,模拟器无法实现 首先需要在AndroidManifest.xml 声明蓝牙权限