Android初识RecyclerView 添加分割线、单击事件、长按事件

一、概述

RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能。
优点:

  • RecyclerView封装了viewholder的回收复用
  • 提供了一种插拔式的体验,高度的解耦,异常的灵活
  • 通过布局管理器LayoutManager可以控制其显示的方式
  • 通过ItemDecoration可以控制Item间的间隔(可绘制)
  • 通过ItemAnimator可以控制Item增删的动画

缺点:

  • 点击、长按事件需要自己实现

RecyclerView.Adapter需要实现3个方法:
1.onCreateViewHolder()
这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,当然这个ViewHolder需要我们自己去编写。直接省去了当初的convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
2.onBindViewHolder()
这个方法主要用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView。
3.getItemCount()
这个方法就类似于BaseAdapter的getCount方法了,即总共有多少个条目。

在项目使用需要添加依赖:

compile 'com.android.support:recyclerview-v7:24.2.1'

二、普通列表

1.实现效果图
Android初识RecyclerView 添加分割线、单击事件、长按事件_第1张图片

2.核心代码

  • 列表页面RecyclerViewActivity.java
package com.czhappy.recyclerviewdemo.activity;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;

import com.czhappy.recyclerviewdemo.R;
import com.czhappy.recyclerviewdemo.adapter.StudentListAdapter;
import com.czhappy.recyclerviewdemo.listener.RecyclerItemClickListener;
import com.czhappy.recyclerviewdemo.model.Student;
import com.czhappy.recyclerviewdemo.view.ItemDivider;

import java.util.ArrayList;
import java.util.List;

import static com.czhappy.recyclerviewdemo.R.id.recyclerView;

/**
 * Description:
 * User: chenzheng
 * Date: 2017/1/18 0018
 * Time: 10:42
 */
public class RecyclerViewActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private List list;

    private StudentListAdapter adapter;

    private int flag = 1;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);

        flag = getIntent().getIntExtra("flag", 1);

        initData();
        initView();
    }

    private void initData() {
        list = new ArrayList();
        for (int i = 0; i < 20; i++) {
            Student s = new Student();
            s.setUserName("我是学生"+i);
            list.add(s);
        }
    }

    private void initView() {
        mRecyclerView = (RecyclerView) this.findViewById(recyclerView);
        //设置布局管理器
        if(flag==1){//普通列表
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        }else{//网格列表
            mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
        }

        //设置adapter
        adapter = new StudentListAdapter(this);
        mRecyclerView.setAdapter(adapter);
        //设置Item增加、移除动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        //添加分割线
        mRecyclerView.addItemDecoration(new ItemDivider().setDividerWith(1).setDividerColor(0xffdddddd));

        mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, mRecyclerView, new RecyclerItemClickListener.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(RecyclerViewActivity.this, "单击:position="+position, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(RecyclerViewActivity.this, "长按:position="+position, Toast.LENGTH_SHORT).show();
            }
        }));

        //添加数据
        adapter.setItems(list);

    }
}
  • 布局文件activity_recyclerview.xml

<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"
        android:scrollbars="vertical"/>

LinearLayout>
  • 适配器StudentListAdapter.java
package com.czhappy.recyclerviewdemo.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.czhappy.recyclerviewdemo.R;
import com.czhappy.recyclerviewdemo.model.Student;

import java.util.ArrayList;
import java.util.List;

/**
 * Description:
 * User: chenzheng
 * Date: 2017/1/18 0018
 * Time: 11:06
 */
public class StudentListAdapter extends RecyclerView.Adapter<StudentListAdapter.StudentViewHolder> {

    private Context mContext;
    private List mList = new ArrayList();


    public StudentListAdapter(Context context) {
        this.mContext = context;
    }

    public void setItems(List list) {
        this.mList = list;
        notifyDataSetChanged();
    }

    @Override
    public StudentListAdapter.StudentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        StudentViewHolder viewHolder = new StudentViewHolder(LayoutInflater.from(mContext)
                .inflate(R.layout.item_student_list, parent, false));
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(StudentListAdapter.StudentViewHolder holder, int position) {

        if(mList!=null && mList.size()>0){
            Student  student = mList.get(position);
            holder.name_tv.setText(student.getUserName());
        }

    }

    @Override
    public int getItemCount() {
        return mList!=null ? mList.size() : 0;
    }

    class StudentViewHolder extends RecyclerView.ViewHolder {

        private TextView name_tv;

        public StudentViewHolder(View itemView) {
            super(itemView);
            name_tv = (TextView) itemView.findViewById(R.id.name_tv);
        }
    }
}
  • 添加分割线通用工具类ItemDivider.java
package com.czhappy.recyclerviewdemo.view;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Description:
 * User: chenzheng
 * Date: 2017/1/18 0018
 * Time: 13:54
 */
public class ItemDivider extends RecyclerView.ItemDecoration {

    private int dividerWith = 1;
    private Paint paint;
    private RecyclerView.LayoutManager layoutManager;

    // 构造方法,可以在这里做一些初始化,比如指定画笔颜色什么的
    public ItemDivider() {
        initPaint();
        paint.setColor(0xffff0000);
    }

    private void initPaint() {
        if (paint == null) {
            paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setStyle(Paint.Style.FILL);
        }
    }

    public ItemDivider setDividerWith(int dividerWith) {
        this.dividerWith = dividerWith;
        return this;

    }

    public ItemDivider setDividerColor(int color) {
        initPaint();
        paint.setColor(color);
        return this;
    }

    /**
     * 指定item之间的间距(就是指定分割线的宽度)   回调顺序 1
     * @param outRect Rect to receive the output.
     * @param view    The child view to decorate
     * @param parent  RecyclerView this ItemDecoration is decorating
     * @param state   The current state of RecyclerView.
     */
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (layoutManager == null) {
            layoutManager = parent.getLayoutManager();
        }
        // 适用 LinearLayoutManager 和 GridLayoutManager
        if (layoutManager instanceof LinearLayoutManager) {
            int orientation = ((LinearLayoutManager) layoutManager).getOrientation();
            if (orientation == LinearLayoutManager.VERTICAL) {
                // 水平分割线将绘制在item底部
                outRect.bottom = dividerWith;
            } else if (orientation == LinearLayoutManager.HORIZONTAL) {
                // 垂直分割线将绘制在item右侧
                outRect.right = dividerWith;
            }
            if (layoutManager instanceof GridLayoutManager) {
                GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) view.getLayoutParams();
                // 如果是 GridLayoutManager 则需要绘制另一个方向上的分割线
                if (orientation == LinearLayoutManager.VERTICAL && lp != null && lp.getSpanIndex() > 0) {
                    // 如果列表是垂直方向,则最左边的一列略过
                    outRect.left = dividerWith;
                } else if (orientation == LinearLayoutManager.HORIZONTAL && lp != null && lp.getSpanIndex() > 0) {
                    // 如果列表是水平方向,则最上边的一列略过
                    outRect.top = dividerWith;
                }
            }
        }
    }

    /**
     * 在item 绘制之前调用(就是绘制在 item 的底层)  回调顺序 2
     * 一般分割线在这里绘制
     * 看到canvas,对自定义控件有一定了解的话,就能想到为什么说给RecyclerView设置分割线更灵活了
     * @param c      Canvas to draw into
     * @param parent RecyclerView this ItemDecoration is drawing into
     * @param state  The current state of RecyclerView
     */
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        // 这个值是为了补偿横竖方向上分割线交叉处间隙
        int offSet = (int) Math.ceil(dividerWith * 1f / 2);
        for (int i = 0; i < parent.getChildCount(); i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            int left1 = child.getRight() + params.rightMargin;
            int right1 = left1 + dividerWith;
            int top1 = child.getTop() - offSet - params.topMargin;
            int bottom1 = child.getBottom() + offSet + params.bottomMargin;
            //绘制分割线(矩形)
            c.drawRect(left1, top1, right1, bottom1, paint);
            int left2 = child.getLeft() - offSet - params.leftMargin;
            int right2 = child.getRight() + offSet + params.rightMargin;
            int top2 = child.getBottom() + params.bottomMargin;
            int bottom2 = top2 + dividerWith;
            //绘制分割线(矩形)
            c.drawRect(left2, top2, right2, bottom2, paint);
        }
    }

    /**
     * 在item 绘制之后调用(就是绘制在 item 的上层)  回调顺序 3
     * 也可以在这里绘制分割线,和上面的方法 二选一
     * @param c      Canvas to draw into
     * @param parent RecyclerView this ItemDecoration is drawing into
     * @param state  The current state of RecyclerView
     */
    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
    }

}
  • 添加单击、长按事件通用工具类RecyclerItemClickListener.java
package com.czhappy.recyclerviewdemo.listener;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

/**
 * Description:
 * User: chenzheng
 * Date: 2017/1/18 0018
 * Time: 14:27
 */
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mListener;

    private GestureDetector mGestureDetector;

    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
        mListener = listener;

        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

                if (childView != null && mListener != null) {
                    mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
        View childView = view.findChildViewUnder(e.getX(), e.getY());

        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        }

        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }
}

三、网格列表

1.实现效果图
Android初识RecyclerView 添加分割线、单击事件、长按事件_第2张图片

RecyclerView在普通列表和网格列表的切换上面做的比较方便,只需要修改LayoutManager参数即可。

if(flag==1){//普通列表
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        }else{//网格列表
            mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
        }

四、源代码下载

http://download.csdn.net/detail/chenzheng8975/9740701

你可能感兴趣的:(Android进阶)