前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android--自定义LayoutManager实现层叠卡片效果

Android--自定义LayoutManager实现层叠卡片效果

作者头像
aruba
发布2020-07-02 15:28:25
2.8K0
发布2020-07-02 15:28:25
举报
文章被收录于专栏:android技术
效果如下:

cardRecyclerView.gif

首先自定义LayouManager,实现自己摆放控件
代码语言:javascript
复制
public class CardLayoutManager extends RecyclerView.LayoutManager {
    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT);
    }

    /**
     * 自定义LayoutManager核心是摆放控件,所以onLayoutChildren方法是我们要改写的核心
     *
     * @param recycler
     * @param state
     */
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        //缓存
        detachAndScrapAttachedViews(recycler);

        //获取所有item(包括不可见的)个数
        int count = getItemCount();
        //由于我们是倒序摆放,所以初始索引从后面开始
        int initIndex = count - CardConfig.SHOW_MAX_COUNT;
        if (initIndex < 0) {
            initIndex = 0;
        }

        for (int i = initIndex; i < count; i++) {
            //从缓存中获取view
            View view = recycler.getViewForPosition(i);
            //添加到recyclerView
            addView(view);
            //测量一下view
            measureChild(view, 0, 0);

            //居中摆放,getDecoratedMeasuredWidth方法是获取带分割线的宽度,比直接使用view.getWidth()精确
            int realWidth = getDecoratedMeasuredWidth(view);
            int realHeight = getDecoratedMeasuredHeight(view);
            int widthPadding = (int) ((getWidth() - realWidth) / 2f);
            int heightPadding = (int) ((getHeight() - realHeight) / 2f);

            //摆放child
            layoutDecorated(view, widthPadding, heightPadding,
                    widthPadding + realWidth, heightPadding + realHeight);
            //根据索引,来位移和缩放child
            int level = count - i - 1;
            //level范围(CardConfig.SHOW_MAX_COUNT-1)- 0
            // 最下层的不动和最后第二层重叠
            if (level == CardConfig.SHOW_MAX_COUNT - 1) {
                level--;
            }
            view.setTranslationY(level * CardConfig.TRANSLATION_Y);
            view.setScaleX(1 - level * CardConfig.SCALE);
            view.setScaleY(1 - level * CardConfig.SCALE);
        }
    }
}
然后利用ItemTouchHelper,对item的移动进行计算,并对每个item进行属性设置
代码语言:javascript
复制
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private List<String> mDatas;
    private RecyclerView.Adapter mAdapter;

    public ItemTouchHelperCallback(List<String> mDatas, RecyclerView.Adapter mAdapter) {
        this.mDatas = mDatas;
        this.mAdapter = mAdapter;
    }

    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {

        return makeMovementFlags(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN);
    }

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

    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
        String s = mDatas.remove(viewHolder.getLayoutPosition());
        mDatas.add(0, s);
        mAdapter.notifyDataSetChanged();
    }

    @Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        //计算移动距离
        float distance = (float) Math.hypot(dX, dY);
        float maxDistance = recyclerView.getWidth() / 2f;

        //比例
        float fraction = distance / maxDistance;
        if (fraction > 1) {
            fraction = 1;
        }
        //为每个child执行动画
        int count = recyclerView.getChildCount();

        for (int i = 0; i < count; i++) {
            //获取的view从下层到上层
            View view = recyclerView.getChildAt(i);

            int level = CardConfig.SHOW_MAX_COUNT - i - 1;
            //level范围(CardConfig.SHOW_MAX_COUNT-1)-0,每个child最大只移动一个CardConfig.TRANSLATION_Y和放大CardConfig.SCALE

            if (level == CardConfig.SHOW_MAX_COUNT - 1) { // 最下层的不动和最后第二层重叠
                view.setTranslationY(CardConfig.TRANSLATION_Y * (level - 1));
                view.setScaleX(1 - CardConfig.SCALE * (level - 1));
                view.setScaleY(1 - CardConfig.SCALE * (level - 1));
            } else if (level > 0) {
                view.setTranslationY(level * CardConfig.TRANSLATION_Y - fraction * CardConfig.TRANSLATION_Y);
                view.setScaleX(1 - level * CardConfig.SCALE + fraction * CardConfig.SCALE);
                view.setScaleY(1 - level * CardConfig.SCALE + fraction * CardConfig.SCALE);
            }
        }

        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }

    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        return 0.3f;
    }
}
再设置给RecyclerView
代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {
    RecyclerView rv;
    List<String> mStrings = new ArrayList<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rv = (RecyclerView) findViewById(R.id.rv);
        rv.setLayoutManager(new CardLayoutManager());
        
        for (int i = 1; i < 21; i++) {
            mStrings.add(String.valueOf(i));
        }
        MyAdapter myAdapter = new MyAdapter(this, mStrings);
        rv.setAdapter(myAdapter);

        ItemTouchHelperCallback itemTouchHelperCallback = new ItemTouchHelperCallback(mStrings, myAdapter);
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchHelperCallback);
        itemTouchHelper.attachToRecyclerView(rv);
    }

    class MyAdapter extends RecyclerView.Adapter {
        private Context mContext;
        private List<String> mStrings;

        public MyAdapter(Context mContext, List<String> mStrings) {
            this.mContext = mContext;
            this.mStrings = mStrings;
        }

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
            return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_recyclerview, viewGroup, false));
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
            MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
            myViewHolder.textView.setText(mStrings.get(i) + "/" + getItemCount());
        }

        @Override
        public int getItemCount() {
            return mStrings.size();
        }

        class MyViewHolder extends RecyclerView.ViewHolder {
            public TextView textView;

            public MyViewHolder(@NonNull View itemView) {
                super(itemView);
                textView = itemView.findViewById(R.id.tv);
            }
        }
    }
}
项目地址:https://gitee.com/aruba/CardMoveApplication.git
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 效果如下:
  • 首先自定义LayouManager,实现自己摆放控件
  • 然后利用ItemTouchHelper,对item的移动进行计算,并对每个item进行属性设置
  • 再设置给RecyclerView
  • 项目地址:https://gitee.com/aruba/CardMoveApplication.git
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档