欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android RecyclerView ItemTouchHelper、自定义LayoutManager

程序员文章站 2022-12-04 21:31:23
绝对的recycler view进阶使用,又精炼简单,get了新技能。 静态界面,自定义layout manager,因为recycler view的layout由layout...

绝对的recycler view进阶使用,又精炼简单,get了新技能。

静态界面,自定义layout manager,因为recycler view的layout由layout manager托管

public class MyLayoutManager extends RecyclerView.LayoutManager{

    public static final int MAX_SHOWN_COUNT = 4;
    public static final float SCALE = 0.05f;
    public static final int TRANS_Y = 30;//需要dp2px

    //其实非常简单 就是layout (RecyclerView的layout是交给lm托管的)
    //第一步只是一次性layout 所以动不起来(因为layout应该还负责移动)

    @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) {
        detachAndScrapAttachedViews(recycler);//报废所有view到recycler里
        int itemCount = getItemCount();
        if (itemCount >= MAX_SHOWN_COUNT) {
            //为什么是最后4个?因为第一个item放在最下面,一张张放上去的
            for (int position = itemCount - MAX_SHOWN_COUNT; position < itemCount; position ++) {
                View view = recycler.getViewForPosition(position);
                addView(view);
                measureChildWithMargins(view, 0, 0);
                int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
                int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
                //居中
                layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
                        widthSpace / 2 + getDecoratedMeasuredWidth(view),
                        heightSpace / 2 + getDecoratedMeasuredHeight(view));
                //顶层scale=1 translationY=0
                //每一级scale相差0.05f translationY=7dp
                //拖动时,顶层scale不变,-1层scale慢慢变为1,transY慢慢变为0(这句话先不考虑)
                //-2层变成-1层
                //-3层scale变化,tranY不变
                int level = itemCount - position - 1;
                //顶层不需要变化
                if (level > 0) {
                    //每一层都要scale变化
                    view.setScaleX(1 - SCALE * level);
                    if (level < MAX_SHOWN_COUNT - 1) {
                        view.setTranslationY(TRANS_Y * level);
                        view.setScaleY(1 - SCALE * level);
                    } else {
                        view.setTranslationY(TRANS_Y * (level - 1));
                        view.setScaleY(1 - SCALE * (level - 1));
                    }
                }
            }
        }
    }
}

动态界面,重写item touch helper callback

class CallBack extends ItemTouchHelper.SimpleCallback {
    public CallBack(int dragDirs, int swipeDirs) {
        super(dragDirs, swipeDirs);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        String s = list.remove(viewHolder.getLayoutPosition());
        list.add(0,s);
        adapter.notifyDataSetChanged();
    }

    @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);
        double swipeValue = Math.sqrt(dX * dX + dY * dY);
        double fraction = swipeValue / (getSwipeThreshold(viewHolder) * recyclerView.getWidth());//阈值
        if (fraction > 1) {
            fraction = 1;
        }
        int childCount = recyclerView.getChildCount();
        for (int i = 0; i < childCount; i ++) {
            View child = recyclerView.getChildAt(i);
            int level = childCount - i - 1;
            if (level > 0) {
                child.setScaleX((float) (1-SCALE * level + fraction * SCALE));

                if (level < MAX_SHOWN_COUNT - 1) {
                    child.setScaleY((float) (1 - SCALE * level + fraction * SCALE));
                    child.setTranslationY((float) (TRANS_Y * level - fraction * TRANS_Y));
                }
            }
        }
    }
}

使用

CallBack callBack = new CallBack(0,
        ItemTouchHelper.DOWN |
                ItemTouchHelper.UP |
                ItemTouchHelper.LEFT |
                ItemTouchHelper.RIGHT);
ItemTouchHelper helper = new ItemTouchHelper(callBack);
helper.attachToRecyclerView(rv);

动画。item touch helper帮你做的工作就是

1.让当前item可拖拽,在item一半的区域被拖到外面时(作者自定义了阈值),移除

2.移除后,下面的view进行补充动画

这里我们需要增加一个补充动画的过度,原生动画太生硬了

就是重写的call back中的onChildDraw

@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);
    double swipeValue = Math.sqrt(dX * dX + dY * dY);
    double fraction = swipeValue / (getSwipeThreshold(viewHolder) * recyclerView.getWidth());//阈值
    if (fraction > 1) {
        fraction = 1;
    }
    int childCount = recyclerView.getChildCount();
    for (int i = 0; i < childCount; i ++) {
        View child = recyclerView.getChildAt(i);
        int level = childCount - i - 1;
        if (level > 0) {
            child.setScaleX((float) (1-SCALE * level + fraction * SCALE));

            if (level < MAX_SHOWN_COUNT - 1) {
                child.setScaleY((float) (1 - SCALE * level + fraction * SCALE));
                child.setTranslationY((float) (TRANS_Y * level - fraction * TRANS_Y));
            }
        }
    }
}