V7-RecyclerView

1- 简单使用

1.1依赖

根据你studio的buildToolsVersion来写(不然编译不通过)。
例如我的buildToolsVersion "25.0.0"
我会这样写(很难找到确定的版本号)(alt+enter)

compile 'com.android.support:recyclerview-v7:25.+'

1.2 设置布局管理器—显示出来的布局风格

有三种风格

//首先设置LayoutManager:控制RecyclerView如何显示布局,系统提供3个布局管理器:
LinearLayoutManager://线性布局,有横向和竖直方向显示
GridLayoutManager://网格布局,有横向和竖直方向显示
StaggeredGridLayoutManager: //瀑布流布局,有横向和竖直方向显示

单列列表

//首先设置布局管理器,就是显示出来的布局的样子,单列列表
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//参数2是否反转布局
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));

多列列表—参数2列数

//多列的规则列表
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
//参数2是否反转布局
recyclerView.setLayoutManager(new GridLayoutManager(this, 3,GridLayoutManager.HORIZONTAL, false));

瀑布流--参数2列数

//多列的不规则的列表,也就是俗称瀑布流效果
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));

1.3 展示数据设置adapter

recyclerView.setAdapter(new MyAdapter());

条目分割线

//条目分割线
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));

**ViewHolder **

class MyHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.iv_image)
    ImageView ivImage;
    @BindView(R.id.tv_text)
    TextView tvText;
    @BindView(R.id.cardVIew)
    CardView cardVIew;

    public MyHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}

MyAdapter

//泛型 viewholder类型
class MyAdapter extends RecyclerView.Adapter {

    //重写onCreateViewHolder--返回一个ViewHolder即可
    @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = View.inflate(parent.getContext(), R.layout.adapter_recycler, null);
        return new MyHolder(view);
    }
    //重写onBindViewHolder设置数据的
    @Override
    public void onBindViewHolder(MyHolder holder, int position) {
        holder.ivImage.setImageResource(Constant.images.get(position));
        holder.tvText.setText("数据 - " + position);
    }
    //重写getItemCount()返回条目数量
    @Override
    public int getItemCount() {
        return Constant.images.size();
    }

}

条目点击事件
设置点击事件,由于RecyclerView没有setOnItemClickListener,只能在Adapter中给View设置Click事件

//设置点击事件
holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(RecyclerViewAcitvity.this, "点击的是:" + position, Toast.LENGTH_SHORT).show();

    }
});

1.4 给条目添加动画

因为在条目中添加动画—因此在adapter中写

public class AnimateAdapter extends CommonAdapter {
    public AnimateAdapter(Context context, int layoutId, List datas) {
        super(context, layoutId, datas);
    }

    @Override
    protected void convert(ViewHolder holder, T t, int position) {
        //给holder的itemView添加动画
        animateHolder(holder);

    }

    protected void animateHolder(ViewHolder holder) {
        //先变小
        holder.itemView.setScaleX(0.5f);
        holder.itemView.setScaleY(0.5f);
        holder.itemView.setRotationX(180);
        //再变大—添加缩放
        ViewCompat.animate(holder.itemView).rotationX(0)
                .scaleX(1f).scaleY(1f)
                .setDuration(1000)
                .setStartDelay(100)
                .setInterpolator(new OvershootInterpolator())
                .start();
    }
}

2 LayoutManager实现卡片层叠布局

  • 1-自定义LayoutManager:extends RecyclerView.LayoutManager
  • 2-重写:onLayoutChildren: layout出我们想要的view即可
  • 3-设置给recyclerview使用
public class OverLayCardLayoutManager extends RecyclerView.LayoutManager {
    private static final String TAG = "swipecard";

    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        Log.e(TAG, "onLayoutChildren() called with: recycler = [" + recycler + "], state = [" + state + "]");

        //轻量级回收 界面上的所有View(如果有view),并且稍后会用到这些view,用detach回收
        //如果是回收以后,稍后不会立刻用到,用recycle回收removeAndRecycleAllViews(recycler);
        detachAndScrapAttachedViews(recycler);

        //获取itemCunt
        int itemCount = getItemCount();
        if (itemCount < 1) {
            return;
        }
        //top-3View的position
        int bottomPosition;
        //边界处理
        if (itemCount < CardConfig.MAX_SHOW_COUNT) {
            bottomPosition = 0;
        } else {
            bottomPosition = itemCount - CardConfig.MAX_SHOW_COUNT;
        }

        //从可见的最底层View开始layout,依次层叠上去
        //循环遍历我们需要的子view
        for (int position = bottomPosition; position < itemCount; position++) {
            //所有LayoutManager需要的子view,通过recycler获取
            View view = recycler.getViewForPosition(position);
            //添加到rv里面
            addView(view);
            //measure
            measureChildWithMargins(view, 0, 0);

            //measure View 水平居中
            //计算x方向和y方向
            int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
            int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
            layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
                    widthSpace / 2 + getDecoratedMeasuredWidth(view),
                    heightSpace / 2 + getDecoratedMeasuredHeight(view));
            /**
             * TopView的Scale 为1,translationY 0
             * 每一级Scale相差0.05f,translationY相差7dp左右
             *
             * 观察人人影视的UI,拖动时,topView被拖动,Scale不变,一直为1.
             * top-1View 的Scale慢慢变化至1,translation也慢慢恢复0
             * top-2View的Scale慢慢变化至 top-1View的Scale,translation 也慢慢变化只top-1View的translation
             * top-3View的Scale要变化,translation岿然不动
             */

            //第几层,举例子,count =7, 最后一个TopView(6)是第0层,
            int level = itemCount - position - 1;
            //除了顶层不需要缩小和位移
            if (level > 0 /*&& level < mShowCount - 1*/) {
                //每一层都需要X方向的缩小(值1表示不应用缩放)(position大 level小 scale大)
                view.setScaleX(1 - CardConfig.SCALE_GAP * level);
                //前N层,依次向下位移和Y方向的缩小
                if (level < CardConfig.MAX_SHOW_COUNT - 1) {
                    //top position大 level小 Translation小(下移)
                    view.setTranslationY(CardConfig.TRANS_Y_GAP * level);
                    view.setScaleY(1 - CardConfig.SCALE_GAP * level);
                } else {//第N层在 向下位移和Y方向的缩小的成都与 N-1层保持一致
                    view.setTranslationY(CardConfig.TRANS_Y_GAP * (level - 1));
                    view.setScaleY(1 - CardConfig.SCALE_GAP * (level - 1));
                }
            }
        }
    }

}
mRv.setLayoutManager(new OverLayCardLayoutManager());

3 ItemTouchHelper实现炫酷动画

ItemTouchHelper--介绍

  • 这货是一个工具类,为RecyclerView扩展滑动消失(删除)和drag & drop效果的
  • 它需要和RecyclerView、Callback 一起工作。Callback 类里定义了 允许哪些交互,并且会接收到对应的交互事件
  • 根据你需要哪种功能(滑动消失(删除)和drag & drop),你需要重写
  • Callback#onMove(RecyclerView, ViewHolder, ViewHolder)—–drag & drop
  • Callback#onSwiped(ViewHolder, int) 方法。 —–滑动消失(删除)

ItemTouchHelper使用

  • 总结一下入门级用法如下,三个步骤:
  • 1 定义一个Callback:ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(int,int),这两个int分别代表要 监听哪几个方向上的拖拽、滑动事件。 常用:ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
  • 2 将Callback传给ItemTouchHelper:ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
  • 3 关联ItemTouchHelper和RecyclerView:itemTouchHelper.attachToRecyclerView(mRv)
  • 4 ItemTouchHelper还负责在其他孩子被拖动后绘制孩子,因此还可以在onChildDraw中进行拖拽时子view的效果
  • ItemTouchHelper就会自动帮我们完成 滑动消失(删除)和drag & drop 的功能。

撸码

public class RenRenCallback extends ItemTouchHelper.SimpleCallback {

    protected RecyclerView mRv;
    protected List mDatas;
    protected RecyclerView.Adapter mAdapter;

    //前一个int是拖拽-后一个int是滑动
    //需要的是滑动消失(删除) ,所以我们的Callback不需要关注onMove()方法。
    public RenRenCallback(RecyclerView rv, RecyclerView.Adapter adapter, List datas) {
        this(0,
                ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT,
                rv, adapter, datas);
    }

    public RenRenCallback(int dragDirs, int swipeDirs
            , RecyclerView rv, RecyclerView.Adapter adapter, List datas) {
        super(dragDirs, swipeDirs);
        mRv = rv;
        mAdapter = adapter;
        mDatas = datas;
    }

    //水平方向是否可以被回收掉的阈值
    public float getThreshold(RecyclerView.ViewHolder viewHolder) {
        //2016 12 26 考虑 探探垂直上下方向滑动,不删除卡片,这里参照源码写死0.5f
        return mRv.getWidth() * /*getSwipeThreshold(viewHolder)*/ 0.5f;
    }

    //在drag & drop 会回调
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    //滑动消失 swipe dismiss 回调  滑动删除动作已经发生后回调的
    //我们先滑动卡片,然后松手,此时ItemTouchHelper判断我们的手势是删除手势,会自动对这个卡片执行丢出屏幕外的动画,同时回调onSwiped()方法。
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        //★实现循环的要点
        //利用当前被删除的View的ViewHolder拿到Position--删除数据集中对应Position的数据源
        Object remove = mDatas.remove(viewHolder.getLayoutPosition());
        //同时将该数据源插入数据集中的首位,第0位
        mDatas.add(0, remove);
        //调用notifyDataSetChanged(),通知列表刷新
        //使用notifyDataSetChanged()原因:即ItemTouchHelper实现的滑动删除,其实只是隐藏了这个滑动的View。并不是真的删除了。
        mAdapter.notifyDataSetChanged();

        //notifyDataSetChanged()会回调LayoutManager.onLayoutChildren()这个函数,
        // 而在这个函数中,我们会重新布局,即真正的移除(不再layout)滑动掉的View,同时会补充进新的最底层的View。
    }


    //ItemTouchHelper还负责在其他孩子被拖动后绘制孩子。
    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        //先根据滑动的dxdy 算出现在动画的比例系数fraction
        double swipValue = Math.sqrt(dX * dX + dY * dY);
        double fraction = swipValue / getThreshold(viewHolder);
        //边界修正 最大为1
        if (fraction > 1) {
            fraction = 1;
        }
        //对每个ChildView进行缩放 位移
        int childCount = recyclerView.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = recyclerView.getChildAt(i);
            //第几层,举例子,count =7, 最后一个TopView(6)是第0层,
            int level = childCount - i - 1;
            if (level > 0) {
                child.setScaleX((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP));

                if (level < MAX_SHOW_COUNT - 1) {
                    child.setScaleY((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP));
                    child.setTranslationY((float) (TRANS_Y_GAP * level - fraction * TRANS_Y_GAP));
                } else {
                    //child.setTranslationY((float) (mTranslationYGap * (level - 1) - fraction * mTranslationYGap));
                }
            }
        }
    }
}
        //step 1
        ItemTouchHelper.Callback callback = new RenRenCallback(mRv, mAdapter, mDatas);
        //step 2
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
        //step 3
        itemTouchHelper.attachToRecyclerView(mRv);

4 实现插入、删除、更新对应的item

通过RecyclerView.Adapter的各notifyItem实现

  • 4.1 notifyDataSetChanged ()
    通知数据发生改变, LayoutManagers将被迫完全重新绑定并重新布局所有可见的视图
  • 4.2 notifyItemChanged (int position, Object payload)
    项目更改事件
    通知该位置处的item其对应的数据发生了改变。
    position 已更改的项目的位置
    payload 可选参数,使用null标识“完整”更新
  • 4.3 notifyItemChanged (int position)
    通知position位置上的item已改变(该位置的数据该更新了),相当于调用notifyItemChanged(position, null);.
    position 已更改的项目的位置
  • 4.4 notifyItemInserted (int position)
    结构性变化事件,反映在position已被新插入,之前在位置的item现在位于position+1
    position 新插入的项目在数据集中的位置
  • 4.5 notifyItemMoved (int fromPosition, int toPosition)
    结构行变化事件,在fromPosition上展示的item已被移动到toPosition
    fromPosition 该item的以前位置。
    toPosition 该item的新位置。
  • 4.6 notifyItemRangeChanged (int positionStart, int itemCount, Object payload)
    item更改事件不是结构更改事件。从positionStart开始的itemCount个项目已经改变
    positionStart 第一项已更改的位置
    itemCount 已更改的项目数量
    payload 可选参数,使用null标识“完整”更新
  • 4.7 notifyItemRangeChanged (int positionStart, int itemCount)
    item更改事件不是结构更改事件。从positionStart开始的itemCount个项目已经改变。相当于notifyItemRangeChanged(position, itemCount, null);.
    positionStart 第一项已更改的位置
    itemCount 已更改的项目数量
  • 4.8 notifyItemRangeInserted (int positionStart, int itemCount)
    从positionStart开始的当前反映的itemCount项目已被新插入。 现在可以在位置positionStart + itemCount处找到之前位于positionStart和之后的项目。
    positionStart 插入的第一个项目的位置
    itemCount 插入的项目数量
  • 4.9 notifyItemRangeRemoved (int positionStart, int itemCount)
    结构性变化事件
    以前位于positionStart的itemCount项目已从数据集中移除。 之前位于positionStart + itemCount之后的项目现在可以在oldPosition - itemCount中找到。
    positionStart 已删除的第一个项目的前一个位置
    itemCount 从数据集中删除的项目数量
  • 4.10 notifyItemRemoved (int position)
    结构性变化事件
    以前位于该position的item已从数据集中移除。 先前位于位置和之后的物品现在可以在oldPosition - 1处找到。
    position 已删除项目的位置

总结和分析几种判断RecyclerView到达底部的方法

参考

http://blog.csdn.net/skykingf/article/details/50827141

你可能感兴趣的:(V7-RecyclerView)