RecyclerView常用功能解析

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

1. RecyclerView常用功能

  • 普通的上下滑动和左右滑动
  • Grid效果上下滑动和左右滑动
  • 瀑布流的上下滑动和左右滑动
  • 添加分割线
  • 添加item之间的空隙
  • 去除最后一个item的分割线
  • 添加点击事件
  • 增加和删除item
  • 下拉刷新和上拉加载
  • 添加头布局和脚布局
  • 拖拽排序和侧滑删除
  • 分页加载、上拉加载、添加脚布局DEMO
  • 2. RecyclerView相关类

  • RecyclerView.Adapter :创建子项item布局和绑定数据
  • RecyclerView.ViewHolder :生成子项item的布局
  • RecyclerView.LayoutManager :设置子项item的排列方式
  • RecyclerView.ItemDecoration : 设置子项item的分割线
  • RecyclerView.ItemAnimator : 设置子项item的动画
  • 3. RecyclerView基本实现

    compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
    
    <?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.support.v7.widget.RecyclerView
            android:id="@+id/main_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </android.support.v7.widget.RecyclerView>
    </LinearLayout>
    
  • 设置布局管理器和Adapter
  • public class MainActivity extends AppCompatActivity {
        private RecyclerView mMain_recyclerview;
        private List<String> mList;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            initView();
            initData();
            initAdapter();
        //初始化控件
        private void initView() {
            setContentView(R.layout.activity_main);
            mMain_recyclerview = (RecyclerView) findViewById(R.id.main_recyclerview);
        //初始化数据
        private void initData() {
            mList = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                mList.add("纵向和横向滑动");
                mList.add("纵向和横向瀑布流");
                mList.add("添加头布局和脚布局");
                mList.add("下拉刷新和上拉加载");
                mList.add("多布局页面");
                mList.add("滑动删除");
                mList.add("点击事件");
                mList.add("添加空布局");
                mList.add("添加分割线");
        //初始化Adapter
        private void initAdapter() {
            //设置布局管理器
            mMain_recyclerview.setLayoutManager(new LinearLayoutManager(this));
            //初始化和设置Adapter
            MainAdapter mainAdapter = new MainAdapter(mList);
            mMain_recyclerview.setAdapter(mainAdapter);
    
  • Adapter:
  • public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
        private List<String> mList;
        public MainAdapter(List<String> list) {
            mList = list;
        //创建子项item的布局
        @Override
        public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_item, parent, false);
            return new ViewHolder(view);
        //给控件设置数据
        @Override
        public void onBindViewHolder(MainAdapter.ViewHolder holder, int position) {
            holder.tv_main.setText(mList.get(position));
        //子项item的数量
        @Override
        public int getItemCount() {
            return mList.size();
        //初始化子项控件
        static class ViewHolder extends RecyclerView.ViewHolder {
            TextView tv_main;
            public ViewHolder(View itemView) {
                super(itemView);
                this.tv_main = itemView.findViewById(R.id.tv_main);
    

    4. RecyclerView左右和上下滑动以及瀑布流:

  • 只需修改布局管理器参数即可:
  • //ListView形式上下滑动:
    mMain_recyclerview.setLayoutManager(new LinearLayoutManager(this));
    //左右滑动:
    LinearLayoutManager magager = new LinearLayoutManager(this);
    magager.setOrientation(LinearLayoutManager.HORIZONTAL);
    //Grid形式上下滑动:
    GridLayoutManager layoutManager = new GridLayoutManager(this,4);
    //Grid形式左右滑动:
    GridLayoutManager layoutManager = new GridLayoutManager(this, 4);
    layoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
    //瀑布流形式上下滑动:
    StaggeredGridLayoutManager layoutManager = new
    StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL);
    //瀑布流形式左右滑动:
    StaggeredGridLayoutManager layoutManager = new
    StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL);
    

    5. ListView形式上下滑动和左右滑动添加分割线:

  • 添加分割线:
  • mMain_recyclerview.addItemDecoration(new MyDividerItemDecoration(this, MyDividerItemDecoration.VERTICAL_LIST));
    
  • MyDividerItemDecoration
    ondraw:绘制 getItemOffsets:绘制的区域
  • public class MyDividerItemDecoration 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 int mOrientation;
        private Drawable mDivider;
        private int mDividerHeight = 2; //默认是2px
        private Paint mPaint;
        //绘制默认分割线
        public MyDividerItemDecoration(Context context, int orientation) {
            final TypedArray a = context.obtainStyledAttributes(ATTRS);
            mDivider = a.getDrawable(0); //系统属性中获取
            a.recycle();
            setOrientation(orientation);
         * 自定义分割线
         * @param context
         * @param orientation 列表方向
         * @param drawableId  分割线图片
        public MyDividerItemDecoration(Context context, int orientation, int drawableId) {
            this(context, orientation);
            mDivider = ContextCompat.getDrawable(context, drawableId);
            mDividerHeight = mDivider.getIntrinsicHeight();
         * 自定义分割线
         * @param context
         * @param orientation   列表方向
         * @param dividerHeight 分割线高度
         * @param dividerColor  分割线颜色
        public MyDividerItemDecoration(Context context, int orientation, int dividerHeight, int dividerColor) {
            this(context, orientation);
            mDividerHeight = dividerHeight;
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setColor(dividerColor);
            mPaint.setStyle(Paint.Style.FILL);
        private void setOrientation(int orientation) {
            if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
                throw new IllegalArgumentException("invalid orientaion");
            mOrientation = orientation;
        @Override //在RecyclerView的onDraw中执行
        public void onDraw(Canvas c, RecyclerView parent) {
            if (mOrientation == VERTICAL_LIST) {
                drawVertical(c, parent);
            } else {
                drawHorizontal(c, 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-1; 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);
        private 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-1; i++) {
                final View child = parent.getChildAt(i);
                RecyclerView v = new 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);
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            if (mOrientation == VERTICAL_LIST) {
                outRect.set(0, 0, 0, mDividerHeight);
            } else {
                outRect.set(0, 0, mDividerHeight, 0);
    

    6. Grid和瀑布流形式添加分割线

  • 添加分割线:
  • mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
    
  • DividerGridItemDecoration(Grid和瀑布流形式都可用):
  • public class DividerGridItemDecoration extends RecyclerView.ItemDecoration
        private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
        private Drawable mDivider;
        public DividerGridItemDecoration(Context context)
            final TypedArray a = context.obtainStyledAttributes(ATTRS);
            mDivider = a.getDrawable(0);
            a.recycle();
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
            drawHorizontal(c, parent);
            drawVertical(c, parent);
        private int getSpanCount(RecyclerView parent)
            // 列数
            int spanCount = -1;
            RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager)
                spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
            } else if (layoutManager instanceof StaggeredGridLayoutManager)
                spanCount = ((StaggeredGridLayoutManager) layoutManager)
                        .getSpanCount();
            return spanCount;
        public void drawHorizontal(Canvas c, RecyclerView parent)
            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.getLeft() - params.leftMargin;
                final int right = child.getRight() + params.rightMargin
                        + mDivider.getIntrinsicWidth();
                final int top = child.getBottom() + params.bottomMargin;
                final int bottom = top + mDivider.getIntrinsicHeight();
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
        public void drawVertical(Canvas c, RecyclerView parent)
            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 top = child.getTop() - params.topMargin;
                final int bottom = child.getBottom() + params.bottomMargin;
                final int left = child.getRight() + params.rightMargin;
                final int right = left + mDivider.getIntrinsicWidth();
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
        private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
                                    int childCount)
            RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager)
                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
                    return true;
            } else if (layoutManager instanceof StaggeredGridLayoutManager)
                int orientation = ((StaggeredGridLayoutManager) layoutManager)
                        .getOrientation();
                if (orientation == StaggeredGridLayoutManager.VERTICAL)
                    if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
                        return true;
                } else
                    childCount = childCount - childCount % spanCount;
                    if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
                        return true;
            return false;
        private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
                                  int childCount)
            RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager)
                childCount = childCount - childCount % spanCount;
                if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
                    return true;
            } else if (layoutManager instanceof StaggeredGridLayoutManager)
                int orientation = ((StaggeredGridLayoutManager) layoutManager)
                        .getOrientation();
                // StaggeredGridLayoutManager 且纵向滚动
                if (orientation == StaggeredGridLayoutManager.VERTICAL)
                    childCount = childCount - childCount % spanCount;
                    // 如果是最后一行,则不需要绘制底部
                    if (pos >= childCount)
                        return true;
                } else
                // StaggeredGridLayoutManager 且横向滚动
                    // 如果是最后一行,则不需要绘制底部
                    if ((pos + 1) % spanCount == 0)
                        return true;
            return false;
        @Override
        public void getItemOffsets(Rect outRect, int itemPosition,
                                   RecyclerView parent)
            int spanCount = getSpanCount(parent);
            int childCount = parent.getAdapter().getItemCount();
            if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
                outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
            } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
                outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
            } else
                outRect.set(0, 0, mDivider.getIntrinsicWidth(),
                        mDivider.getIntrinsicHeight());
    

    7. 添加item之间的空隙

    public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
        private int leftRight;
        private int topBottom;
        public SpacesItemDecoration(int leftRight, int topBottom) {
            this.leftRight = leftRight;
            this.topBottom = topBottom;
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
          super.onDraw(c, parent, state);
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
            //竖直方向的
            if (layoutManager.getOrientation() == LinearLayoutManager.VERTICAL) {
                //最后一项需要 bottom
                if (parent.getChildAdapterPosition(view) == layoutManager.getItemCount() - 1) {
                    outRect.bottom = topBottom;
                outRect.top = topBottom;
                outRect.left = leftRight;
                outRect.right = leftRight;
            } else {
                //最后一项需要right
                if (parent.getChildAdapterPosition(view) == layoutManager.getItemCount() - 1) {
                    outRect.right = leftRight;
                outRect.top = topBottom;
                outRect.left = leftRight;
                outRect.bottom = topBottom;
    
    int leftRight = DisplayUtil.dp2px(8);
    int topBottom = DisplayUtil.dp2px(8);
    mRecyclerView.addItemDecoration(new SpacesItemDecoration(leftRight, topBottom));
    

    8. RecyclerView去除最后一个item的分割线

  • ListView形式:在上面的分割线绘制部分,我们只绘制了childCount-1个,所以上面的分割线,已经不会绘制最后一条item的分割线了。

  • Grid和瀑布流形式:首先去判断是不是最后一行或者一列,然后在getItemOffsets方法中不绘制底部或者右边,上面的部分已经实现。

  • 9. RecyclerView添加点击事件

  • 处理点击事件,只需要在Adapter中处理即可(不推荐)
  • public class PortraitAdapter extends RecyclerView.Adapter<PortraitAdapter.ViewHolder> {
        private List<Fruit> mFruitList;
        private boolean flag = true;
        public PortraitAdapter(List<Fruit> fruitList) {
            mFruitList = fruitList;
        static class ViewHolder extends RecyclerView.ViewHolder {
            ImageView fruitImage;
            TextView fruitName;
            LinearLayout ll_portraitscape;
            public ViewHolder(View view) {
                super(view);
                fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
                fruitName = (TextView) view.findViewById(R.id.fruit_name);
                ll_portraitscape = (LinearLayout) view.findViewById(R.id.ll_portraitscape);
        @Override
        public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_portrait, parent, false);
            final ViewHolder holder = new ViewHolder(view);
            holder.ll_portraitscape.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    new AlertDialog.Builder(v.getContext())
                            .setTitle("确认删除吗")
                            .setNegativeButton("取消",null)
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (flag == true){
                                        removeData(holder.getAdapterPosition());
                                        flag=false;
                                    }else{
                                        addData(holder.getAdapterPosition());
                                        flag=true;
                            .show();
                    return false;
            holder.fruitImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(parent.getContext(),"我是图片短点击",Toast.LENGTH_SHORT).show();
            return holder;
        @Override
        public void onBindViewHolder(final ViewHolder holder, int position) {
            Fruit fruit = mFruitList.get(position);
            holder.fruitImage.setImageResource(fruit.getImageId());
            holder.fruitName.setText(fruit.getName());
        @Override
        public int getItemCount() {
            return mFruitList.size();
        public void addData(int position) {
            mFruitList.add(position, new Fruit("Apple", R.drawable.apple_pic));
            notifyItemInserted(position);
        public void removeData(int position) {
            mFruitList.remove(position);
            notifyItemRemoved(position);
    只需要在onCreateViewHolder中处理即可,可以很轻松实现子项中任意控件或布局的点击事件。
    
  • 在Adapter中定义接口并提供回调(推荐)
  • Adapter:
    public interface OnItemClickListener{
        void onItemClick(View view,int position);
        void onItemLongClick(View view,int position);
    public void setOnItemClickListener(OnItemClickListener mOnItemClickListener){
        this.mOnItemClickListener = mOnItemClickListener;
    
    onBindViewHolder:
    if (mOnItemClickListener!=null){
        holder.tv.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                int pos = holder.getLayoutPosition();
                mOnItemClickListener.onItemClick(holder.tv,pos);
        holder.tv.setOnLongClickListener(new View.OnLongClickListener(){
            @Override
            public boolean onLongClick(View view){
                int pos = holder.getLayoutPosition();
                mOnItemClickListener.onItemLongClick(holder.tv,pos);
                return false;
    
    Activity:
    mHomeAdapter.setOnItemClickListener(new HomeAdapter.OnItemClickListener(){
        @Override
        public void onItemClick(View view,int position){
        @Override
        public void onItemLongClick(View view,final int position){
    

    10. RecyclerView增加和删除item

  • 在Adapter添加两种方法
  • public void addData(int position) {
            mFruitList.add(position, new Fruit("Apple", R.drawable.apple_pic));
            notifyItemInserted(position);
        public void removeData(int position) {
            mFruitList.remove(position);
            notifyItemRemoved(position);
    
  • 在Adapter中的onCreateViewHolder中的点击事件里面添加动作
  • holder.ll_portraitscape.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    new AlertDialog.Builder(v.getContext())
                            .setTitle("确认删除吗")
                            .setNegativeButton("取消",null)
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (flag == true){
                                        removeData(holder.getAdapterPosition());
                                        flag=false;
                                    }else{
                                        addData(holder.getAdapterPosition());
                                        flag=true;
                            .show();
                    return false;
    

    11. RecyclerView添加动画效果

  • 默认的动画:
  • mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    
  • 自定义的动画:
  • private int mLastPosition;//放在成员变量的位置上
    if (viewHolder.getAdapterPosition() > mLastPosition) {
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewHolder.itemView, "scaleX", 0.5f, 1f);
        scaleX.start();
        mLastPosition = viewHolder.getLayoutPosition();
    

    说明:实现的方式有很多种,这里介绍一种,就是在RecyclerView的onBindViewHolder中利用属性动画就可以实现非常华丽的效果。

    12. RecyclerView多布局

  • 实现多布局最核心的方法就是在Adapter中重写getItemViewType方法:
  • @Override
    public int getItemViewType(int position) {
        if (mNewsBeanList.get(position).getThumbnail_pic_s03() == null) {
            return IMAGE_ONLY_ONE;
        } else {
            return IMAGE_TWOORTHREE;
    

    说明:判断下布局的不同,返回不同的值,不同的值就代表了不多的布局。

  • 在onCreateViewHolder方法中第二个参数对应的就是上面方法返回的值,我们根据值的不同,填充不同的布局。
  • @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        if (viewType == IMAGE_TWOORTHREE) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.news_imagethree_item, viewGroup, false);
             ImageThreeViewHolder viewHolder = new ImageThreeViewHolder(view);
            return viewHolder;
        } else {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.news_imageonly_item, viewGroup, false);
            ImageOnlyOneViewHolder viewHolder = new ImageOnlyOneViewHolder(view);
            return viewHolder;
    
  • 不同的布局需要不同的ViewHolder
  •     static class ImageThreeViewHolder extends RecyclerView.ViewHolder {
            private TextView mTv_title;
            private ImageView mIv_image01;
            private ImageView mIv_image02;
            private ImageView mIv_image03;
            private TextView mTv_company;
            private TextView mTv_time;
            private View mItemView;
            public ImageThreeViewHolder(View itemView) {
                super(itemView);
                mItemView = itemView;
                mTv_title = itemView.findViewById(R.id.tv_title);
                mIv_image01 = itemView.findViewById(R.id.iv_image01);
                mIv_image02 = itemView.findViewById(R.id.iv_image02);
                mIv_image03 = itemView.findViewById(R.id.iv_image03);
                mTv_company = itemView.findViewById(R.id.tv_company);
                mTv_time = itemView.findViewById(R.id.tv_time);
        static class ImageOnlyOneViewHolder extends RecyclerView.ViewHolder {
            private View mItemView;
            private TextView mTv_title;
            private TextView mTv_company;
            private TextView mTv_time;
            private ImageView mIv_image01;
            public ImageOnlyOneViewHolder(View itemView) {
                super(itemView);
                mItemView = itemView;
                mTv_title = itemView.findViewById(R.id.tv_title);
                mTv_company = itemView.findViewById(R.id.tv_company);
                mTv_time = itemView.findViewById(R.id.tv_time);
                mIv_image01 = itemView.findViewById(R.id.iv_image01);
    
  • onBindViewHolder方法中的第一个参数对应不同的viewholder,我们通过判断,来进行每个元素的写入
  • @Override
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
            if (viewHolder instanceof ImageThreeViewHolder) {
                ((ImageThreeViewHolder) viewHolder).mTv_title.setText(mNewsBeanList.get(position).getTitle());
                ((ImageThreeViewHolder) viewHolder).mTv_company.setText(mNewsBeanList.get(position).getAuthor_name());
                ((ImageThreeViewHolder) viewHolder).mTv_time.setText(mNewsBeanList.get(position).getDate());
                Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s()).into(((ImageThreeViewHolder) viewHolder).mIv_image01);
                Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s02()).into(((ImageThreeViewHolder) viewHolder).mIv_image02);
                Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s03()).into(((ImageThreeViewHolder) viewHolder).mIv_image03);
            } else if (viewHolder instanceof ImageOnlyOneViewHolder) {
                ((ImageOnlyOneViewHolder) viewHolder).mTv_title.setText(mNewsBeanList.get(position).getTitle());
                ((ImageOnlyOneViewHolder) viewHolder).mTv_company.setText(mNewsBeanList.get(position).getAuthor_name());
                ((ImageOnlyOneViewHolder) viewHolder).mTv_time.setText(mNewsBeanList.get(position).getDate());
                Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s()).into(((ImageOnlyOneViewHolder) viewHolder).mIv_image01);
    

    13. RecyclerView 上拉刷新和下拉加载

  • 下拉刷新(借助SwipeRefreshLayout)
  • private void initRefresh() { srRefresh.setColorSchemeResources(R.color.colorPrimary); srRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { refreshFruits(); private void refreshFruits() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { initFruits(); adapter.notifyDataSetChanged(); srRefresh.setRefreshing(false); }).start(); private void initFruits() { fruitList.clear(); for (int i = 0; i < 50; i++) { Random random = new Random(); int index = random.nextInt(fruits.length); fruitList.add(fruits[index]);

    说明:SwipeRefreshLayout设置一个监听器:setOnRefreshListener,onRefresh方法中进行数据更新的操作。

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {
                            mHandler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
                            }, 500);
                        if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {
                            mHandler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
                            }, 500);
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
    

    说明:recyclerView添加滑动监听器addOnScrollListener,在onScrollStateChanged方法中处理加载的动作。

    14. RecyclerView添加头布局和脚布局

    添加头布局和脚布局,其实和实现多布局一模一样,不再赘述。

    15. RecyclerView拖曳排序和侧滑删除

    private void initBind() {
            //为RecycleView绑定触摸事件
            ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
                @Override
                public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                    //侧滑删除
                    int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                    //首先回调的方法 返回int表示是否监听该方向
                    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//拖拽
                    return makeMovementFlags(dragFlags, swipeFlags);
                @Override
                public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                    //滑动事件
                    Collections.swap(list, viewHolder.getAdapterPosition(), target.getAdapterPosition());
                    adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
                    return false;
                @Override
                public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                    //侧滑事件
                    list.remove(viewHolder.getAdapterPosition());
                    adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
                @Override
                public boolean isLongPressDragEnabled() {
                    //是否可拖拽
                    return true;
            helper.attachToRecyclerView(recyclerView);
    

    16. 分页加载、上拉加载、添加脚布局DEMO

    分页加载的核心代码:

    private final int PAGE_COUNT = 10;
    
    adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);
    
    private List<String> getDatas(final int firstIndex, final int lastIndex) {
            List<String> resList = new ArrayList<>();
            for (int i = firstIndex; i < lastIndex; i++) {
                if (i < list.size()) {
                    resList.add(list.get(i));
            return resList;
        private void updateRecyclerView(int fromIndex, int toIndex) {
            List<String> newDatas = getDatas(fromIndex, toIndex);
            if (newDatas.size() > 0) {
                adapter.updateList(newDatas, true);
            } else {
                adapter.updateList(null, false);
    

    Adapter:

    public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        private List<String> datas;
        private Context context;
        private int normalType = 0;
        private int footType = 1;
        private boolean hasMore = true;
        private boolean fadeTips = false;
        private Handler mHandler = new Handler(Looper.getMainLooper());
        private static final String TAG = "MyAdapter";
        public MyAdapter(List<String> datas, Context context, boolean hasMore) {
            this.datas = datas;
            this.context = context;
            this.hasMore = hasMore;
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == normalType) {
                return new NormalHolder(LayoutInflater.from(context).inflate(R.layout.item, null));
            } else {
                return new FootHolder(LayoutInflater.from(context).inflate(R.layout.footview, null));
        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof NormalHolder) {
                ((NormalHolder) holder).textView.setText(datas.get(position));
            } else {
                ((FootHolder) holder).tips.setVisibility(View.VISIBLE);
                if (hasMore == true) {
                    fadeTips = false;
                    if (datas.size() > 0) {
                        ((FootHolder) holder).tips.setText("正在加载更多...");
                } else {
                    if (datas.size() > 0) {
                        ((FootHolder) holder).tips.setText("没有更多数据了");
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                ((FootHolder) holder).tips.setVisibility(View.GONE);
                                fadeTips = true;
                                hasMore = true;
                        }, 500);
        @Override
        public int getItemCount() {
            return datas.size() + 1;
        public int getRealLastPosition() {
            return datas.size();
        public void updateList(List<String> newDatas, boolean hasMore) {
            if (newDatas != null) {
                datas.addAll(newDatas);
            this.hasMore = hasMore;
            notifyDataSetChanged();
        class NormalHolder extends RecyclerView.ViewHolder {
            private TextView textView;
            public NormalHolder(View itemView) {
                super(itemView);
                textView = (TextView) itemView.findViewById(R.id.tv);
        class FootHolder extends RecyclerView.ViewHolder {
            private TextView tips;
            public FootHolder(View itemView) {
                super(itemView);
                tips = (TextView) itemView.findViewById(R.id.tips);
        public boolean isFadeTips() {
            return fadeTips;
        public void resetDatas() {
            datas = new ArrayList<>();
        @Override
        public int getItemViewType(int position) {
            Log.e(TAG,"getItemCount()::"+getItemCount());
            Log.e(TAG,"position::"+position);
            if (position == getItemCount() - 1) {
                return footType;
            } else {
                return normalType;
    

    Activity:

    public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
        private SwipeRefreshLayout refreshLayout;
        private RecyclerView recyclerView;
        private List<String> list;
        private int lastVisibleItem = 0;
        private final int PAGE_COUNT = 10;
        private LinearLayoutManager mLayoutManager;
        private MyAdapter adapter;
        private Handler mHandler = new Handler(Looper.getMainLooper());
        private static final String TAG = "MainActivity";
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initData();
            findView();
            initRefreshLayout();
            initRecyclerView();
        private void initData() {
            list = new ArrayList<>();
            for (int i = 1; i <= 40; i++) {
                list.add("条目" + i);
        private void findView() {
            refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refreshLayout);
            recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        private void initRefreshLayout() {
            refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,
                    android.R.color.holo_orange_light, android.R.color.holo_green_light);
            refreshLayout.setOnRefreshListener(this);
        private void initRecyclerView() {
            adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);
            mLayoutManager = new LinearLayoutManager(this);
            recyclerView.setLayoutManager(mLayoutManager);
            recyclerView.setAdapter(adapter);
            recyclerView.setItemAnimator(new DefaultItemAnimator());
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {
                            mHandler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
                            }, 500);
                        if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {
                            mHandler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    Log.e(TAG, "lastVisibleItem::" + lastVisibleItem);
                                    Log.e(TAG, "adapter.getItemCount()::" + adapter.getItemCount());
                                    updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
                            }, 500);
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
                    Log.e(TAG, "lastVisibleItem::" + lastVisibleItem);
                    Log.e(TAG, "adapter.getItemCount()::" + adapter.getItemCount());
        private List<String> getDatas(final int firstIndex, final int lastIndex) {
            List<String> resList = new ArrayList<>();
            for (int i = firstIndex; i < lastIndex; i++) {
                if (i < list.size()) {
                    resList.add(list.get(i));
            return resList;
        private void updateRecyclerView(int fromIndex, int toIndex) {
            List<String> newDatas = getDatas(fromIndex, toIndex);
            if (newDatas.size() > 0) {
                adapter.updateList(newDatas, true);
            } else {
                adapter.updateList(null, false);
        @Override
        public void onRefresh() {
            refreshLayout.setRefreshing(true);
            adapter.resetDatas();
            updateRecyclerView(0, PAGE_COUNT);
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    refreshLayout.setRefreshing(false);
            }, 1000);