艺术控件RecyclerView的交互动画&bug解决

前言

        RecyclerView是Google在support-v7里面添加的控件,是5.0 Material Design模式下的一员,在众多的App中使用非常频繁,之前是ListView现在是RecyclerView,想比之下RecyclerView更加的灵活,高内聚低耦合,将ListView功能进行了拆分,各个类各司其职构成了现在的RecyclerView。现在我们来玩一下RecyclerView的交互动画和解决一下bug。

效果~

Part 1、RecyclerView动画交互

RecyclerView的设置

        rv = (RecyclerView) findViewById(R.id.rv);
        rv.setLayoutManager(new LinearLayoutManager(this));
        adapter = new MyAdapter(DataUtils.init(),this);
        rv.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));
        rv.setAdapter(adapter);
        helper = new ItemTouchHelper(new MyItemTouchCallBack(adapter));
        helper.attachToRecyclerView(rv);
tips:
1、DividerItemDecoration() : 是Android support-v7提供的默认分隔线

2、要实现拖拽、侧滑效果需要继承ItemTouchCallBack类

3、attachToRecyclerView() : 将ItemTouCallBack包装之后的ItemTouchHelper类关联到RecyclerView上

接下来我们定义MyItemTouchCallBack类继承ItemTouchCallBack类

public class MyItemTouchCallBack extends ItemTouchHelper.Callback {
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        int flag = makeMovementFlags(dragFlag, swipeFlag);
        return flag;
    }
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder src, RecyclerView.ViewHolder target) {
        return true;
    }
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    }
}
tips:

1、getMoveMentFlags() : CallBack回调监听时先调用,用来判断当前是什么动作(上下还是左右),上面指定的是上下拖拽、左右侧滑的效果,如果你的RecyclerView是横向则相反

2、onMove() : 当移动的时候回调的拖拽方法

3、onSwiped()  : 当侧滑的时候回调

效果~


然而当拖拽、侧滑的时候其它Item并没有随着移动,所以要实现这种效果需要让Adapter不断的去刷新notifyItemMoved & notifyItemRemoved;又因为在拖拽和侧滑的过程中会不断调用onMove和onSwipe方法,所以只需要在这两个方法里面调用Adapter的notify方法即可。

定义接口,通过接口对象调用

public interface ItemTouchMoveListener {

    /**
     * 当拖拽的时候回调</br>
     * 可以在此方法里面实现:拖拽条目并实现刷新效果
     * @param fromPosition 从什么位置拖
     * @param toPosition	到什么位置
     * @return 是否执行了move
     */
    boolean onItemMove(int fromPosition, int toPosition);

    /**
     * 当条目被移除是回调
     * @param position 移除的位置
     * @return
     */
    boolean onItemRemove(int position);
}
调用的方法

    //当移动的时候回调的方法--拖拽
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder src, RecyclerView.ViewHolder target) {
        if (src.getItemViewType() != target.getItemViewType()) {
            return false;
        }
        // 在拖拽的过程当中不断地调用adapter.notifyItemMoved(from,to);
        mTouchMoveListener.onItemMove(src.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    //侧滑的时候回调的
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        mTouchMoveListener.onItemRemove(viewHolder.getAdapterPosition());
    }
tips:

1、

        if (src.getItemViewType() != target.getItemViewType()) {
            return false;
        }
判断的意义在于在RecyclerView可能每个Item的类型是不同的,但是默认情况是相同的可以忽略

被调用的方法

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        Collections.swap(list, fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    @Override
    public boolean onItemRemove(int position) {
        list.remove(position);
        notifyItemRemoved(position);
        return true;
    }
tips:

1、不管是移动还是移除都遵循两步:(1)处理数据 (2)进行刷新

这样Item的动画就形成了

效果~

这里也提一下,虽然RecyclerView提供了拖拽和侧滑动画,但是你也可以手动的去触发它们

helper.startDrag(viewHolder);

从效果图中看到选中和未选中背景是一样样的,看着挺不爽,幸运的是在ItemTouchCallBack类提供了

    //为选中设置背景颜色
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        //判断选中状态
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            viewHolder.itemView.setBackgroundColor(Color.parseColor("#66666666"));
        }
        super.onSelectedChanged(viewHolder, actionState);
    }
    //取消选中的背景颜色
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        if (viewHolder != null) {
            viewHolder.itemView.setBackgroundColor(Color.WHITE);
        }
        super.clearView(recyclerView, viewHolder);
    }
就这样就解决了我们的需求,不得不说RecyclerView很贴心

最后RecyclerView当然也提供给我们实现每个Item滑动时候的动画效果,只需要在onChildDraw()实现相应的方法即可

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        //dX:水平方向移动的增量  0~1
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            float alpha = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
            viewHolder.itemView.setAlpha(alpha);//1~0
            viewHolder.itemView.setScaleX(alpha);//1~0
            viewHolder.itemView.setScaleY(alpha);//1~0
        }
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }
效果~

ok,效果完成

Part 2、RecyclerView交互动画bug解决

当最后的那个效果如果你向下滑动会看到会有好多空的Item

为什么会发生这种情况呢?其实你仔细观察空白的是有规律的,像RecyclerView和ListView都会去复用ItemView,当你移除之后便没有了复用的View,所以会显示空白。

解决办法很多,只需要你在恢复删除的ItemView即可

因为每当删除ItemView时会调用clearView方法,所以在这里恢复比较合适

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        if (viewHolder != null) {
            viewHolder.itemView.setBackgroundColor(Color.WHITE);
            // 恢复
            viewHolder.itemView.setAlpha(1);//1~0
            viewHolder.itemView.setScaleX(1);//1~0
            viewHolder.itemView.setScaleY(1);//1~0
        }
        super.clearView(recyclerView, viewHolder);
    }
这样,bug问题就解决了~






  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值