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

Android实现可拖动层叠卡片布局

程序员文章站 2022-04-14 11:41:07
公司app要求做一个扭蛋功能,其实就是一个可拖动层叠卡片列表,原理还是由一个自定义recyclerview和layoutmanager来实现自定义recyclerview很简单,只是修改touch事件...

公司app要求做一个扭蛋功能,其实就是一个可拖动层叠卡片列表,原理还是由一个自定义recyclerview和layoutmanager来实现

自定义recyclerview很简单,只是修改touch事件,防止点击到卡片外还被处理的情况

@override
    public boolean ontouchevent(motionevent e) {
        if(e.gety()< uiutil.dip2px(tutuapplication.getinstance().getcontext(),95)||e.gety()>getheight()-uiutil.dip2px(tutuapplication.getinstance().getcontext(),95)){
            if(e.getaction()!=motionevent.action_up && e.getaction()!=motionevent.action_move) {
                return false;
            }
        }
        return super.ontouchevent(e);
    }

实际的层叠效果还是需要layoutmanager来实现

public class swipecardlayoutmanager extends recyclerview.layoutmanager {
    context context;
    int trans_y_gap;
    public swipecardlayoutmanager(context context){
        trans_y_gap= (int) typedvalue.applydimension(typedvalue.complex_unit_dip,15,
                context.getresources().getdisplaymetrics());
    }
    @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) {
        super.onlayoutchildren(recycler, state);
        //1.如何实现层叠效果--cardview.layout(l,t,r,b)
        //2.如何让8个条目中的4个展示在recylerview里面
        //1在布局layout之前,将所有的子view先全部detach掉,然后放到scrap集合里面缓存。
        detachandscrapattachedviews(recycler);
        //2)只将最上面4个view添加到recylerview容器里面
        int itemcount=getitemcount();//8个
        int bottomposition;
        if(itemcount< cardconfig.max_show_count){
            bottomposition=0;
 
        }else{
            bottomposition=itemcount-cardconfig.max_show_count;
        }
        for(int i=bottomposition;i<itemcount;i++){
            view view=recycler.getviewforposition(i);
            addview(view);
            measurechildwithmargins(view,0,0);
            int widthspace=getwidth()-getdecoratedmeasuredwidth(view);
            int heightspace=getheight()-getdecoratedmeasuredheight(view);
            //摆放cardview
            //层叠效果--scale+translationy
            //层级的位置关系1/2/3/4
            int level=itemcount-i-1;
            layoutdecorated(view,
                    widthspace/2,
                    heightspace/2+statusbarutil.getstatusbarheight(tutuapplication.getinstance().getcontext()),
                    widthspace/2+getdecoratedmeasuredwidth(view),
                    heightspace/2+statusbarutil.getstatusbarheight(tutuapplication.getinstance().getcontext())+getdecoratedmeasuredheight(view));
 
            if(level>0){
                if(level<cardconfig.max_show_count){
                    view.settranslationy(cardconfig.trans_v_gap*level*1.3f);
                    view.setscalex(1-cardconfig.scale_gap*level);
                    view.setscaley(1-cardconfig.scale_gap*level);
                }
            }else {
                view.settranslationy(cardconfig.trans_v_gap*(level-1));
                view.setscalex(1-cardconfig.scale_gap*(level-1));
                view.setscaley(1-cardconfig.scale_gap*(level-1));
            }
        }
 
    }
}

显示出来就是这个样子

Android实现可拖动层叠卡片布局

对于滑动显示下一张,则使用自定义itemtouchhelper.simplecallback来展示

自定义itemtouchhelper.simplecallback

public class swipecardcallback extends itemtouchhelper.simplecallback {
    private gamegachaadapter adapter;
    private recyclerview mrv;
    private onswipeendlistener listener;
    private textview tv;
    private int x = 1;
    private context context;
 
    public void refresh(){
//        x = 1;
//        tv.settext(context.getresources().getstring(r.string.explored)+(++x)+"/????");
        removecard();
    }
    public swipecardcallback(gamegachaadapter adapter, recyclerview mrv, textview view, context context) {
        super(0,
                itemtouchhelper.left | itemtouchhelper.up |
                        itemtouchhelper.right | itemtouchhelper.down
        );
        this.adapter = adapter;
        this.mrv = mrv;
        this.tv = view;
        this.context = context;
    }
    public void addgamegachalist(list<imultypehelper> mdatas){
        adapter.addadapterdata(0,mdatas);
        adapter.notifydatasetchanged();
        listener.onswipe();
    }
    public swipecardcallback(int dragdirs, int swipedirs) {
        super(dragdirs, swipedirs);
    }
 
    public swipecardcallback() {
        /*
        * 即我们对哪些方向操作关心。如果我们关心用户向上拖动,可以将
         填充swipedirs参数为left | right 。0表示从不关心。
        * */
        super(0,
                itemtouchhelper.left | itemtouchhelper.up |
                        itemtouchhelper.right | itemtouchhelper.down
        );
    }
 
 
    @override
    public boolean onmove(recyclerview recyclerview,
                          recyclerview.viewholder viewholder,
                          recyclerview.viewholder target) {
        return false;
    }
 
    @override
    public void onswiped(recyclerview.viewholder viewholder, int direction) {
        //当已经滑动删除了的时候会被回掉--删除数据,循环的效果
        removecard();
    }
 
    public void removecard() {
        if(adapter!=null && adapter.getitemcount()>0) {
            adapter.removeadapterdata(adapter.getitemcount() - 1);
//        mdatas.add(0, remove);
            adapter.notifydatasetchanged();
            listener.onswipe();
            if (adapter.getitemcount() == 6) {
                listener.onswipeend();
            }
            tv.settext(context.getresources().getstring(r.string.explored) + (++x) + "/????");
        }
    }
 
    @override
    public void clearview(@nonnull recyclerview recyclerview, @nonnull recyclerview.viewholder viewholder) {
        super.clearview(recyclerview, viewholder);
    }
 
    @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);
        //监听话滑动的距离--控制动画的执行程度
 
        if(dy == 0f&&!iscurrentlyactive){
            int itemcount = recyclerview.getchildcount();
            for (int i = 0; i < itemcount; i++) {
                //执行
                view view = recyclerview.getchildat(i);
                //几个view层叠的效果,错开的效果--便宜动画+缩放动画
                int level = itemcount - i - 1;
                view.setrotation(0);
                if(dx == 0) {
                    if(level>0){
                        if(level<cardconfig.max_show_count){
                            view.settranslationy(cardconfig.trans_v_gap*level*1.3f);
                            view.setscalex(1-cardconfig.scale_gap*level);
                            view.setscaley(1-cardconfig.scale_gap*level);
                        }
                    }else {
                        view.settranslationy(cardconfig.trans_v_gap*(level-1));
                        view.setscalex(1-cardconfig.scale_gap*(level-1));
                        view.setscaley(1-cardconfig.scale_gap*(level-1));
                    }
                }
            }
        }else {
            //灵界点
            double maxdistance = recyclerview.getwidth() * 1f;
            double distance = math.sqrt(dx * dx)*2;
            //动画执行的百分比
            double fraction = distance / maxdistance;
            if (fraction > 1) {
                fraction = 1;
            }
            int itemcount = recyclerview.getchildcount();
            for (int i = 0; i < itemcount; i++) {
                //执行
                view view = recyclerview.getchildat(i);
                //几个view层叠的效果,错开的效果--便宜动画+缩放动画
                int level = itemcount - i - 1;
                if(level == 0){//最外层动画
                    if(math.abs(dx) == 1080f && dy == 0f&&!iscurrentlyactive){
                        view.setrotation(0);
                    }else {
                        if(dx<0){
                            view.setrotation((float) (360f - (30 * fraction)));
                        }else {
                            view.setrotation((float) (30 * fraction));
                        }
                    }
                } else if(level ==cardconfig.max_show_count-1){//最内层动画
                    view.settranslationy((float) (cardconfig.trans_v_gap*(level-fraction)*1.3f));
                    view.setscalex((float) (1-cardconfig.scale_gap*(level-fraction)));
                    view.setscaley((float) (1-cardconfig.scale_gap*(level-fraction)));
                }else if (level < cardconfig.max_show_count - 1) {
                    view.settranslationy((float) ((level - (2*fraction)) * cardconfig.trans_v_gap));
                    view.setscalex((float) (1 - cardconfig.scale_gap * level + fraction * (cardconfig.scale_gap*2)));
                    view.setscaley((float) (1 - cardconfig.scale_gap * level + fraction * (cardconfig.scale_gap*2)));
                }
 
            }
        }
 
    }
 
    @override
    public void onselectedchanged(@nullable recyclerview.viewholder viewholder, int actionstate) {
        super.onselectedchanged(viewholder, actionstate);
    }
 
    public interface onswipeendlistener{
        void onswipeend();
        void onswipe();
    }
    public void setonswipeendlistener(onswipeendlistener listener){
        this.listener = listener;
    }
}

在activity中:

private swipecardcallback callback;
private itemtouchhelper helper; 
 
...
helper = new itemtouchhelper(callback);
 helper.attachtorecyclerview(swipeflingadapterview);
 callback.setonswipeendlistener(new swipecardcallback.onswipeendlistener() {
            @override
            public void onswipeend() {
                swipeflingadapterview.suppresslayout(true);
                gamegacharefresh.setclickable(false);
                toastutils.createtoast().showcenter(tutugamegachaactivity.this,getstring(r.string.wait_moment));
                presenter.getgamegacha(presenter_load_state_refresh);
            }
 
            @override
            public void onswipe() {
                if(arrayadapter.getitemcount()>0) {
                    swipe();
                }
            }
 
        });

这样实际效果就差不多可以了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。