高仿支付宝增加减少item功能和动画效果

闲来无事,看了下支付宝App做的应用item效果,很炫,效果如下:

自己实现的效果如下:

gif可能有点卡,但是实现了支付宝效果,

说下思路:下面是实例图(凑合看吧,大概意思是)

开始是打算用ScrollView+RecycleView实现,上面一个RecycleView是存储已经添加的app图标区域,下面做一个linearLayout,动态添加RecycleView,因为下面的项目是多个的,动态获取的,可以实现动态添加项目,但是没有动画效果,因为所有的item不是在一个组件里面实现的,功能是实现了,但是没有动画效果,距离支付宝的效果还有距离,于是换一个思想

,把上面和下面的都放在一个RecycleView里面,就是整个界面只有一个RecycleView,并且把每一类item数据放到一个list中,头部添加的也是单独的list,整个数据全部方法一个bean中,bean中数据是这样的结构:list在存每个item的list

public class AllApplyTable implements Serializable {
    private int type;
    private String titleName;
    private List<ApplyTable> mList;

有人说,支付宝的不是有title么,这样婶儿的:

good question!确实,recycleView的adapter里面可以通过

getItemViewType()方法返回不同的试图,但是这个地方因为是用的
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4, LinearLayoutManager.VERTICAL, false);

如果单独的返回不同的试图,界面会出现错乱,title的位置不会单独占用一行,但是GridLayoutManager有个类

 GridLayoutManager.SpanSizeLookup,这个类有个重写的方法:
getSpanSize(int positon),这个方法返回的的意思是当前的item占几行,比如当前是title试图,那么就单独占一行,所以根据type返回item占的数量:
@Override
public int getSpanSize(int position) {
    int type = mApplyAdapter.getItemViewType(position);
    switch (type){
        case 0:
            return 4;
         default:
             return 1;
    }
}

解决了title单独占一行的问题,注意:title也是一个bean和item一样,不过是某些属性不一样来区分是title还是item

然后还有一个拖动的效果,就是可以左右上下拖动,如果是LinearLayoutManager只可以上下拖动,我们需要继承

ItemTouchHelper.Callback所以ItemDragHelperCallback 类这样:
public class ItemDragHelperCallback extends ItemTouchHelper.Callback {
    private OnItemMoveListener mOnItemMoveListener;
    private boolean mIsLongPressEnabled;

    public void setLongPressEnabled(boolean longPressEnabled) {
        mIsLongPressEnabled = longPressEnabled;
    }

    public interface OnItemMoveListener {
        boolean onItemMove(int fromPosition, int toPosition);
    }

    //相当于 set 设置监听 传入ChannelAdapter中的OnItemMoveListener对象
    public ItemDragHelperCallback(OnItemMoveListener onItemMoveListener) {
        mOnItemMoveListener = onItemMoveListener;
    }

    //返回true 允许拖拽
    @Override
    public boolean isLongPressDragEnabled() {
        return mIsLongPressEnabled;
    }

    //返回可以滑动的方向,比如说允许从右到左侧滑,允许上下拖动等
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int itemViewType = viewHolder.getItemViewType();
        if (1!= itemViewType){
            return makeMovementFlags(0, 0);
        }
        //根据recyclerView的布局,进行设置拖拽的方向
        int dragFlags = setDragFlags(recyclerView);
        //不允许进行滑动
        int swipeFlags = 0;
        // 获取触摸响应的方向   包含两个 1.拖动dragFlags 2.侧滑删除swipeFlags
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    private int setDragFlags(RecyclerView recyclerView) {
        int dragFlags;
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager || layoutManager instanceof StaggeredGridLayoutManager) {
            dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        } else {
            dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        }
        return dragFlags;
    }

    //当用户拖动一个Item进行上下移动从旧的位置到新的位置的时候会调用该方法,在该方法内,
    // 我们可以调用Adapter的notifyItemMoved方法来交换两个ViewHolder的位置,最后返回true,
    // 表示被拖动的ViewHolder已经移动到了目的位置。所以,如果要实现拖动交换位置,可以重写该方法(前提是支持上下拖动)
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

        //不同Type之间不允许移动
        if (viewHolder.getItemViewType() != target.getItemViewType()) {
            return false;
        }
        return mOnItemMoveListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setBackgroundColor(Color.WHITE);
        //当用户操作完毕某个item并且其动画也结束后会调用该方法,一般我们在该方法内恢复ItemView的初始状态,防止由于复用而产生的显示错乱问题。
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        //当用户左右滑动Item达到删除条件时,会调用该方法,一般手指触摸滑动的距离达到RecyclerView宽度的一半时,
        // 再松开手指,此时该Item会继续向原先滑动方向滑过去并且调用onSwiped方法进行删除,否则会反向滑回原来的位置。
        //如果在onSwiped方法内我们没有进行任何操作,即不删除已经滑过去的Item,那么就会留下空白的地方,
        // 因为实际上该ItemView还占据着该位置,只是移出了我们的可视范围内罢了。
    }

    //拖动选择状态改变回调
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        super.onSelectedChanged(viewHolder, actionState);
        //从静止状态变为拖拽或者滑动的时候会回调该方法,参数actionState表示当前的状态。
        /**
         * ACTION_STATE_IDLE:拖拽或删除结束,这时 viewHolder 参数为 null 。
         * ACTION_STATE_DRAG:开始拖拽
         * ACTION_STATE_SWIPE:开始删除
         */
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            // ItemTouchHelper.ACTION_STATE_IDLE 看看源码解释就能理解了
            // 侧滑或者拖动的时候背景设置为灰色
            viewHolder.itemView.setBackgroundColor(Color.GRAY);
        }
    }
}

 

在Activity里面使用 的时候是:

            ApplyAdapter allAdapter = new ApplyAdapter(this, allTablesApply);
            GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4, LinearLayoutManager.VERTICAL, false);
            mRv_head.setLayoutManager(gridLayoutManager);
            mRv_head.setItemAnimator(new MydefaultAnimator());
            AdapterColSpanLookup mAdapterColSpanLookup = new AdapterColSpanLookup(allAdapter);
//设置AdapterColSpanLookup返回item和title占的个数
            gridLayoutManager.setSpanSizeLookup(mAdapterColSpanLookup);
            mRv_head.setAdapter(allAdapter);
            ItemDragHelperCallback callback = new ItemDragHelperCallback(allAdapter);
//            //是一个工具类,可实现侧滑删除和拖拽移动,完成后数据的刷新(UI更新)由重写的ItemDragHelperCallback完成
            ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
//            //调用ItemTouchHelper的attachToRecyclerView方法建立联系
            touchHelper.attachToRecyclerView(mRv_head);
            allAdapter.setItemDragHelperCallback(callback);

我们还需要定义下那些可以拖动哪些不能拖动,最近添加的在recycle上面的就是可以拖动的,其他下面的不允许拖动:

在ItemDragHelperCallback类的getMovementFlags里面获取itemViewType值,区分是否是已经添加到头部,如果是添加才可以拖动,否则不能拖动

int itemViewType = viewHolder.getItemViewType();
if (1!= itemViewType){
    return makeMovementFlags(0, 0);
}

还有一个需要解决的问题是怎么移动,就是当前点击的时候怎么移动到特定的位置,分为下面移动到上面,我们就直接从下面list中删除对应的bean,我们暂且叫list_1,然后添加到头部list,我们暂且叫:headList,

list_1.remove(bean)

headList.add(bean)

就完成下面的删除,上面的添加,然后,在统一添加到adapte的list中,我们设置的时候有个动画:

mRv_head.setItemAnimator(new MydefaultAnimator());mRv_head是recycleView

MydefaultAnimator时候实现SimpleItemAnimator接口的类,是默认的动画

最后执行上面删除执行:allTablesApply是adapter全部list数据

moveEnd = allTablesApply.indexOf(at);
allAdapter.notifyItemMoved(position, moveEnd);
allAdapter.notifyItemRangeChanged(moveEnd-1,allTablesApply.size());

上面添加执行:

appayTableUser是头部已经添加的数据集合

allAdapter.notifyItemMoved(position, appayTableUser.size() - 1);
allAdapter.notifyItemRangeChanged(0,position+1);

最后实现高仿支付宝APP的添加删除item效果,有问题可以留言。

源码下载:

https://download.csdn.net/download/u012106080/11892097


版权声明:本文为u012106080原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>