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

Android星球效果实现

程序员文章站 2022-06-24 15:28:05
在项目中看着这个旋转效果挺炫的,就抽取出来做个记录。主要是使用CarrouselLayout 稍微修改 CarrouselLayout代码Demo下载z地址:GitHub https://github.com/lyfkai/AndroidCarrouselLayout 主要代码如下 : public ......

Android星球效果实现

 

在项目中看着这个旋转效果挺炫的,就抽取出来做个记录。主要是使用carrousellayout 稍微修改

 

carrousellayout代码demo下载z地址:github

https://github.com/lyfkai/androidcarrousellayout

 

主要代码如下 :

 

public class carrousellayout extends relativelayout {

    private context mcontext;
    //自动旋转 默认不自动
    private boolean mautorotation;

    //旋转间隔时间  默认设置为2秒
    private int mrotationtime;

    //旋转木马旋转半径  圆的半径
    private float mcarrouselr;

    //camera和旋转木马距离
    private float mdistance = 2f * mcarrouselr;

    //旋转方向 分0顺时针和 1逆时针 俯视旋转木马看
    private int mrotatedirection;

    //handler
    private carrouselrotatehandler mhandler;

    //手势处理
    private gesturedetector mgesturedetector;

    //x旋转
    private int mrotationx;

    //z旋转
    private int mrotationz;

    //旋转的角度
    private float mangle = 0;

    //旋转木马子view
    private list<view> mcarrouselviews = new arraylist<>();

    //旋转木马子view的数量
    private int viewcount;

    //半径扩散动画
    private valueanimator manimationr;

    //记录最后的角度 用来记录上一次取消touch之后的角度
    private float mlastangle;

    //是否在触摸
    private boolean istouching;

    //旋转动画
    private valueanimator restanimator;

    //选中item
    private int selectitem;

    //item选中回调接口
    private oncarrouselitemselectedlistener moncarrouselitemselectedlistener;

    //item点击回调接口
    private oncarrouselitemclicklistener moncarrouselitemclicklistener;

    //x轴旋转动画
    private valueanimator xanimation;

    //z轴旋转动画
    private valueanimator zanimation;

    private boolean isfinish = true;//惯性动画是否结束
    private boolean isfling;

    public carrousellayout(context context) {
        this(context, null);
    }

    public carrousellayout(context context, attributeset attrs) {
        this(context, attrs, 0);
    }

    public carrousellayout(context context, attributeset attrs, int defstyleattr) {
        super(context, attrs, defstyleattr);
        init(context, attrs);
    }

    private void init(context context, attributeset attrs) {
        this.mcontext = context;
        typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.carrousellayout);
        mautorotation = typedarray.getboolean(r.styleable.carrousellayout_autorotation, false);
        mrotationtime = typedarray.getint(r.styleable.carrousellayout_rotationtime, 2000);
        mcarrouselr = typedarray.getdimension(r.styleable.carrousellayout_r, 200);
        mrotatedirection = typedarray.getint(r.styleable.carrousellayout_rotatedirection, 0);
        typedarray.recycle();
        mgesturedetector = new gesturedetector(context, getgesturedetectorcontroller());
        inithandler();
    }

    /**
     * 初始化handler对象
     */
    private void inithandler() {
        mhandler = new carrouselrotatehandler(mautorotation, mrotationtime, mrotatedirection) {
            @override
            public void onrotating(carrouselrotatedirection rotatedirection) {//接受到需要旋转指令
                try {
                    if (viewcount != 0) {//判断自动滑动从那边开始
                        int perangle = 0;
                        switch (rotatedirection) {
                            case clockwise:
                                perangle = 360 / viewcount;
                                break;
                            case anticlockwise:
                                perangle = -360 / viewcount;
                                break;
                        }
                        if (mangle == 360) {
                            mangle = 0f;
                        }

                        if (isfinish)
                            startanimrotation(mangle + perangle, null);
                    }
                } catch (exception e) {
                    e.printstacktrace();
                }

            }
        };
    }


    private gesturedetector.simpleongesturelistener getgesturedetectorcontroller() {

        return new gesturedetector.simpleongesturelistener() {

            @override
            public boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) {
                isfling = true;

                if (e2.getx() - e1.getx() < 0) { // 左滑
                    setautoscrolldirection(carrouselrotatedirection.clockwise);
                } else {
                    setautoscrolldirection(carrouselrotatedirection.anticlockwise);
                }
                return true;
            }

            @override
            public boolean onscroll(motionevent e1, motionevent e2, float distancex, float distancey) {
                isfling = false;
                if (distancex > 0) { // 左滑
                    setautoscrolldirection(carrouselrotatedirection.clockwise);
                } else {
                    setautoscrolldirection(carrouselrotatedirection.anticlockwise);
                }
                //转换成弧度
                double radians = math.toradians(mrotationz);
                //math.cos(radians) 返回对应的radians弧度的余弦值
                mangle += math.cos(radians) * (distancex / 4) + math.sin(radians) * (distancey / 4);
                // log.e("mangle", mangle + "");
                log.e("mrotationz", mrotationz + "");
                //初始化
                refreshlayout();
                return true;
            }


        };
    }

    /**
     * 初始化 计算平均角度后各个子view的位置
     */
    public void refreshlayout() {
        for (int i = 0; i < mcarrouselviews.size(); i++) {
            double radians = mangle + 180 - i * 360 / viewcount;
            float x0 = (float) math.sin(math.toradians(radians)) * mcarrouselr;
            float y0 = (float) math.cos(math.toradians(radians)) * mcarrouselr;
            float scale0 = (mdistance - y0) / (mdistance + mcarrouselr);
            mcarrouselviews.get(i).setscalex(scale0 < 0.5f ? 0.5f : scale0);
            mcarrouselviews.get(i).setscaley(scale0 < 0.5f ? 0.5f : scale0);
            if (mcarrouselviews.get(i) instanceof relativelayout) {
                if (((relativelayout) mcarrouselviews.get(i)).getchildcount() >= 2) {
                    if (((relativelayout) mcarrouselviews.get(i)).getchildat(0) instanceof imageview) {
                        int value = float.valueof((scale0 < 0.5f ? 0.5f : scale0) * 255).intvalue();
                        ((imageview) ((relativelayout) mcarrouselviews.get(i)).getchildat(0)).setimagealpha(value);
//                        ((imageview)((relativelayout) mcarrouselviews.get(i)).getchildat(0)).setalpha(scale0);
                    }
//                    ((relativelayout) mcarrouselviews.get(i)).getchildat(0).setalpha(scale0);
                    if (((relativelayout) mcarrouselviews.get(i)).getchildat(1) instanceof textview) {
                        ((relativelayout) mcarrouselviews.get(i)).getchildat(1).setalpha(scale0 < 0.5f ? 0.5f : scale0);
                    }
                }
            }
            float rotationx_y = (float) math.sin(math.toradians(mrotationx * math.cos(math.toradians(radians)))) * mcarrouselr;
            float rotationz_y = -(float) math.sin(math.toradians(-mrotationz)) * x0;
            float rotationz_x = (((float) math.cos(math.toradians(-mrotationz)) * x0) - x0);
            mcarrouselviews.get(i).settranslationx(x0 + rotationz_x);
            mcarrouselviews.get(i).settranslationy(rotationx_y + rotationz_y);
        }
        list<view> arrayviewlist = new arraylist<>();
        arrayviewlist.clear();
        for (int i = 0; i < mcarrouselviews.size(); i++) {
            arrayviewlist.add(mcarrouselviews.get(i));
        }
        sortlist(arrayviewlist);
        postinvalidate();
    }

    /**
     * 排序
     * 對子view 排序,然后根据变化选中是否重绘,这样是为了实现view 在显示的时候来控制当前要显示的是哪三个view,可以改变排序看下效果
     *
     * @param list
     */
    @suppresswarnings("unchecked")
    private <t> void sortlist(list<view> list) {
        @suppresswarnings("rawtypes")
        comparator comparator = new sortcomparator();
        t[] array = list.toarray((t[]) new object[list.size()]);
        arrays.sort(array, comparator);
        int i = 0;
        listiterator<t> it = (listiterator<t>) list.listiterator();
        while (it.hasnext()) {
            it.next();
            it.set(array[i++]);
        }
        for (int j = 0; j < list.size(); j++) {
            list.get(j).bringtofront();
        }
    }

    /**
     * 筛选器
     */
    private class sortcomparator implements comparator<view> {
        @override
        public int compare(view o1, view o2) {
            return (int) (1000 * o1.getscalex() - 1000 * o2.getscalex());
        }
    }


    @override
    protected void onsizechanged(int w, int h, int oldw, int oldh) {
        super.onsizechanged(w, h, oldw, oldh);
        refreshlayout();
        if (mautorotation) {
            mhandler.sendemptymessage(carrouselrotatehandler.mmsgwhat);
        }
    }

    @override
    protected void onlayout(boolean changed, int l, int t, int r, int b) {
        super.onlayout(changed, l, t, r, b);
        if (changed) {
            checkchildview();
            startanimationr();
        }
    }

    /**
     * 旋转木马半径打开动画
     */
    public void startanimationr() {
        startanimationr(1f, mcarrouselr);
    }

    /**
     * 旋转木马半径动画
     *
     * @param isopen 是否打开  否则关闭
     */
    public void startanimationr(boolean isopen) {
        if (isopen) {
            startanimationr(1f, mcarrouselr);
        } else {
            startanimationr(mcarrouselr, 1f);
        }
    }

    /**
     * 半径扩散、收缩动画 根据设置半径来实现
     *
     * @param from
     * @param to
     */
    public void startanimationr(float from, float to) {
        manimationr = valueanimator.offloat(from, to);
        manimationr.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator valueanimator) {
                mcarrouselr = (float) valueanimator.getanimatedvalue();
                refreshlayout();
            }
        });
        manimationr.setinterpolator(new decelerateinterpolator());
        manimationr.setduration(0);
        manimationr.start();
    }

    public void checkchildview() {
        //先清空views里边可能存在的view防止重复
        for (int i = 0; i < mcarrouselviews.size(); i++) {
            mcarrouselviews.remove(i);
        }
        final int count = getchildcount(); //获取子view的个数
        viewcount = count;
        for (int i = 0; i < count; i++) {
            final view view = getchildat(i); //获取指定的子view
            final int position = i;
            mcarrouselviews.add(view);
            view.setonclicklistener(new onclicklistener() {
                @override
                public void onclick(view v) {
                    if (moncarrouselitemclicklistener != null) {
                        moncarrouselitemclicklistener.onitemclick(view, position);
                    }
                }
            });

        }

    }

    /**
     * 复位
     */
    private void restview() {
        if (viewcount == 0) {
            return;
        }
        float resultangle = 0;
        //平均角度
        float averageangle = 360 / viewcount;
        if (mangle < 0) {
            averageangle = -averageangle;
        }
        float minvalue = (int) (mangle / averageangle) * averageangle;//最小角度
        float maxvalue = (int) (mangle / averageangle) * averageangle + averageangle;//最大角度
        if (mangle >= 0) {//分为是否小于0的情况
            if (mangle - mlastangle > 0) {
                resultangle = maxvalue;
            } else {
                resultangle = minvalue;
            }
        } else {
            if (mangle - mlastangle < 0) {
                resultangle = maxvalue;
            } else {
                resultangle = minvalue;
            }
        }
        startanimrotation(resultangle, null);
    }


    /**
     * 动画旋转
     *
     * @param resultangle
     * @param complete
     */
    private void startanimrotation(float resultangle, final runnable complete) {
        if (mangle == resultangle) {
            return;
        }
        if (!isfinish) {
            restanimator = valueanimator.offloat(mangle, mangle + (resultangle - mangle) * 5);
            //设置旋转匀速插值器
            restanimator.setinterpolator(new decelerateinterpolator());
            restanimator.setduration(1000);
        } else {
            restanimator = valueanimator.offloat(mangle, resultangle);
            //设置旋转匀速插值器
            restanimator.setinterpolator(new linearinterpolator());
            restanimator.setduration(8000);
        }

        restanimator.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator animation) {
                if (istouching == false) {
                    mangle = (float) animation.getanimatedvalue();
                    refreshlayout();
                }
            }
        });
        restanimator.addlistener(new animator.animatorlistener() {
            @override
            public void onanimationstart(animator animation) {

            }

            @override
            public void onanimationend(animator animation) {
                if (istouching == false) {
                    selectitem = calculateitem();
                    if (selectitem < 0) {
                        selectitem = viewcount + selectitem;
                    }
                    if (moncarrouselitemselectedlistener != null) {
                        moncarrouselitemselectedlistener.selected(mcarrouselviews.get(selectitem), selectitem);
                    }

                    if (isfinish == false) {
                        isfinish = true;
                    }
                    isfling = false;
                }
            }

            @override
            public void onanimationcancel(animator animation) {

            }

            @override
            public void onanimationrepeat(animator animation) {

            }
        });
        restanimator.start();
    }

    /**
     * 通过角度计算是第几个item
     *
     * @return
     */
    private int calculateitem() {
        return (int) (mangle / (360 / viewcount)) % viewcount;
    }

    /**
     * 触摸停止计时器
     */
    @override
    public boolean dispatchtouchevent(motionevent ev) {
        return setcanautorotation(ev);
    }

    /**
     * 触摸方法
     *
     * @param event
     * @return
     */
    @override
    public boolean ontouchevent(motionevent event) {
        return true;
    }

    /**
     * 触摸时停止自动加载
     *
     * @param event
     */

    float downx = 0;
    float downy = 0;
    long currentms = 0;

    float movex;
    float movey;
    long movetime;


    public boolean setcanautorotation(motionevent event) {

        boolean result = mgesturedetector.ontouchevent(event);
        if (result) {
            this.getparent().requestdisallowintercepttouchevent(true);//通知父控件勿拦截本控件
        }
        if (event.getaction() == motionevent.action_move) {
            if (!result) {
                this.getparent().requestdisallowintercepttouchevent(true);//通知父控件勿拦截本控件
            }
        }


        switch (event.getaction()) {
            case motionevent.action_down:
                mlastangle = mangle;
                downx = event.getx();//float downx
                downy = event.gety();//float downy
                currentms = system.currenttimemillis();//long currentms     获取系统时间

                break;
            case motionevent.action_move:
                movex = event.getx() - downx;//x轴距离
                movey = event.gety() - downy;//y轴距离
                movetime = system.currenttimemillis() - currentms;//移动时间

                if (math.abs(movex) > 50 && movetime > 50) {
                    istouching = true;
                    isfinish = true;

                    stopautorotation();
                }

                break;
            case motionevent.action_up:
            case motionevent.action_cancel:
                if (math.abs(movex) > 50 && movetime > 50) {
                    istouching = false;
                    isfinish = true;
                    if (isfling) {
                        isfinish = false;
                    } else {
                        isfinish = true;
                    }
                    restview();
                    resumeautorotation();
                }
                break;
        }
        return super.dispatchtouchevent(event);
    }

    /**
     * 停止自动加载
     */
    public void stopautorotation() {
        if (mhandler != null && mautorotation) {
            mhandler.removemessages(carrouselrotatehandler.mmsgwhat);
        }
    }

    /**
     * 从新启动自动加载
     */
    public void resumeautorotation() {
        if (mhandler != null && mautorotation) {
            mhandler.sendemptymessagedelayed(carrouselrotatehandler.mmsgwhat, 1000);
        }
    }

    /**
     * 获取所有的view
     *
     * @return
     */
    public list<view> getviews() {
        return mcarrouselviews;
    }

    /**
     * 获取角度
     *
     * @return
     */
    public float getangle() {
        return mangle;
    }


    /**
     * 设置角度
     *
     * @param angle
     */
    public void setangle(float angle) {
        this.mangle = angle;
    }

    /**
     * 获取距离
     *
     * @return
     */
    public float getdistance() {
        return mdistance;
    }

    /**
     * 设置距离
     *
     * @param distance
     */
    public void setdistance(float distance) {
        this.mdistance = distance;
    }

    /**
     * 获取半径
     *
     * @return
     */
    public float getr() {
        return mcarrouselr;
    }

    /**
     * 获取选择是第几个item
     *
     * @return
     */
    public int getselectitem() {
        return selectitem;
    }

    /**
     * 设置选中方法
     *
     * @param selectitem
     */
    public void setselectitem(int selectitem) {
        if (selectitem >= 0) {
            float angle = 0;
            if (getselectitem() == 0) {
                if (selectitem == mcarrouselviews.size() - 1) {
                    angle = mangle - (360 / viewcount);
                } else {
                    angle = mangle + (360 / viewcount);
                }
            } else if (getselectitem() == mcarrouselviews.size() - 1) {
                if (selectitem == 0) {
                    angle = mangle + (360 / viewcount);
                } else {
                    angle = mangle - (360 / viewcount);
                }
            } else {
                if (selectitem > getselectitem()) {
                    angle = mangle + (360 / viewcount);
                } else {
                    angle = mangle - (360 / viewcount);
                }
            }

            float resultangle = 0;
            float part = 360 / viewcount;
            if (angle < 0) {
                part = -part;
            }
            //最小角度
            float minvalue = (int) (angle / part) * part;
            log.e("minvalue", minvalue + "");
            //最大角度
            float maxvalue = (int) (angle / part) * part;

            if (angle >= 0) {//分为是否小于0的情况
                if (angle - mlastangle > 0) {
                    resultangle = maxvalue;
                    log.e("maxvalue", resultangle + "");
                } else {
                    resultangle = minvalue;
                    log.e("maxvalue", resultangle + "");
                }
            } else {
                if (angle - mlastangle < 0) {
                    resultangle = maxvalue;
                } else {
                    resultangle = minvalue;
                }
            }

            if (viewcount > 0) startanimrotation(resultangle, null);
        }
    }

    /**
     * 设置半径
     *
     * @param r
     */
    public carrousellayout setr(float r) {
        this.mcarrouselr = r;
        mdistance = 2f * r;
        return this;
    }

    /**
     * 选中回调接口实现
     *
     * @param moncarrouselitemselectedlistener
     */
    public void setoncarrouselitemselectedlistener(oncarrouselitemselectedlistener moncarrouselitemselectedlistener) {
        this.moncarrouselitemselectedlistener = moncarrouselitemselectedlistener;
    }

    /**
     * 点击事件回调
     *
     * @param moncarrouselitemclicklistener
     */
    public void setoncarrouselitemclicklistener(oncarrouselitemclicklistener moncarrouselitemclicklistener) {
        this.moncarrouselitemclicklistener = moncarrouselitemclicklistener;
    }


    /**
     * 设置是否自动切换
     *
     * @param autorotation
     */
    public carrousellayout setautorotation(boolean autorotation) {
        this.mautorotation = autorotation;
        mhandler.setautorotation(autorotation);
        return this;
    }

    /**
     * 获取自动切换时间
     *
     * @return
     */
    public long getautorotationtime() {
        return mhandler.getmrotationtime();
    }

    /**
     * 设置自动切换时间间隔
     *
     * @param autorotationtime
     */
    public carrousellayout setautorotationtime(long autorotationtime) {
        if (mhandler != null)
            mhandler.setmrotationtime(autorotationtime);
        return this;
    }

    /**
     * 是否自动切换
     *
     * @return
     */
    public boolean isautorotation() {
        return mautorotation;
    }

    /**
     * 设置自动选择方向
     *
     * @param mcarrouselrotatedirection
     * @return
     */
    public carrousellayout setautoscrolldirection(carrouselrotatedirection mcarrouselrotatedirection) {
        if (mhandler != null)
            mhandler.setmrotatedirection(mcarrouselrotatedirection);
        return this;
    }

    public void createxanimation(int from, int to, boolean start) {
        if (xanimation != null) if (xanimation.isrunning() == true) xanimation.cancel();
        xanimation = valueanimator.ofint(from, to);
        xanimation.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator animation) {
                mrotationx = (integer) animation.getanimatedvalue();
                refreshlayout();
            }
        });
        xanimation.setinterpolator(new linearinterpolator());
        xanimation.setduration(2000);
        if (start) xanimation.start();
    }


    public valueanimator createzanimation(int from, int to, boolean start) {
        if (zanimation != null) if (zanimation.isrunning() == true) zanimation.cancel();
        zanimation = valueanimator.ofint(from, to);
        zanimation.addupdatelistener(new valueanimator.animatorupdatelistener() {
            @override
            public void onanimationupdate(valueanimator animation) {
                mrotationz = (integer) animation.getanimatedvalue();
                refreshlayout();
            }
        });
        zanimation.setinterpolator(new linearinterpolator());
        zanimation.setduration(2000);
        if (start) zanimation.start();
        return zanimation;
    }


    public carrousellayout setrotationx(int mrotationx) {
        this.mrotationx = mrotationx;
        return this;
    }

    public carrousellayout setrotationz(int mrotationz) {
        this.mrotationz = mrotationz;
        return this;
    }

    public float getrotationx() {
        return mrotationx;
    }

    public int getrotationz() {
        return mrotationz;
    }

    public valueanimator getrestanimator() {
        return restanimator;
    }

    public valueanimator getanimationr() {
        return manimationr;
    }

    public void setanimationz(valueanimator zanimation) {
        this.zanimation = zanimation;
    }

    public valueanimator getanimationz() {
        return zanimation;
    }

    public void setanimationx(valueanimator xanimation) {
        this.xanimation = xanimation;
    }

    public valueanimator getanimationx() {
        return xanimation;
    }


}

 

handler消息机制控制动态及旋转

 

package com.example.administrator.icome.carrousellayout;


import android.os.handler;
import android.os.message;

/**
 * 旋转木马自动旋转控制handler
 * created by dalong on 2016/11/12.
 */

public abstract class carrouselrotatehandler extends handler {
    //消息what
    public static final int mmsgwhat = 1000;
    //是否旋转
    private boolean isautorotation;
    //旋转事件间隔
    private  long mrotationtime;
    //消息对象
    private message message;
    //旋转方向
    private carrouselrotatedirection  mrotatedirection;

    public carrouselrotatehandler(boolean isautorotation, int mrotationtime , int mrotatedirection) {
        this.isautorotation = isautorotation;
        this.mrotationtime = mrotationtime;
        this.mrotatedirection=mrotatedirection==0?carrouselrotatedirection.clockwise:carrouselrotatedirection.anticlockwise;
        message=createmessage();
        setautorotation(isautorotation);
    }

    /**
     * 消息处理
     * @param msg
     */
    @override
    public void handlemessage(message msg) {
        super.handlemessage(msg);
        switch (msg.what){
            case mmsgwhat:
                //如果自动旋转
                if(isautorotation){
                    //旋转通知
                    onrotating(mrotatedirection);
                    //再次发送消息  循环
                    sendmessage();
                }
                break;
        }
    }

    /**
     * 需要旋转通知方法
     */
    public abstract void onrotating(carrouselrotatedirection mrotatedirection);

    /**
     * 创建消息对象
     * @return
     */
    private message createmessage(){
        message message=new message();
        message.what=mmsgwhat;
        return  message;
    }

    /**
     * 发送消息
     */
    public void sendmessage(){
        //清除所有mmsgwhat的消息
        try {
            removemessages(mmsgwhat);
        } catch (exception e) {
        }
        message=createmessage();
        this.sendmessagedelayed(message,mrotationtime);

    }

    /**
     * 获取是否自动旋转
     * @return
     */
    public boolean isautorotation() {
        return isautorotation;
    }

    /**
     * 设置是否自动旋转
     * @param autorotation
     */
    public void setautorotation(boolean autorotation) {
        isautorotation = autorotation;
        if(autorotation){//如果需要旋转
            sendmessage();
        }else{//不需要旋转  需要清除所有消息队列中的消息
            removemessages(mmsgwhat);
        }
    }

    /**
     * 获取旋转事件间隔
     * @return
     */
    public long getmrotationtime() {
        return mrotationtime;
    }

    /**
     * 设置旋转事件间隔
     * @param mrotationtime
     */
    public void setmrotationtime(long mrotationtime) {
        this.mrotationtime = mrotationtime;
    }

    /**
     * 获取旋转方向
     * @return
     */
    public carrouselrotatedirection getmrotatedirection() {
        return mrotatedirection;
    }

    /**
     * 设置旋转方向
     * @param mrotatedirection
     */
    public void setmrotatedirection(carrouselrotatedirection mrotatedirection) {
        this.mrotatedirection = mrotatedirection;
    }

}

 

 

 

 

 

 

public class carrousellayout extends relativelayout {

private context mcontext;
//自动旋转 默认不自动
private boolean mautorotation;

//旋转间隔时间 默认设置为2秒
private int mrotationtime;

//旋转木马旋转半径 圆的半径
private float mcarrouselr;

//camera和旋转木马距离
private float mdistance = 2f * mcarrouselr;

//旋转方向 分0顺时针和 1逆时针 俯视旋转木马看
private int mrotatedirection;

//handler
private carrouselrotatehandler mhandler;

//手势处理
private gesturedetector mgesturedetector;

//x旋转
private int mrotationx;

//z旋转
private int mrotationz;

//旋转的角度
private float mangle = 0;

//旋转木马子view
private list<view> mcarrouselviews = new arraylist<>();

//旋转木马子view的数量
private int viewcount;

//半径扩散动画
private valueanimator manimationr;

//记录最后的角度 用来记录上一次取消touch之后的角度
private float mlastangle;

//是否在触摸
private boolean istouching;

//旋转动画
private valueanimator restanimator;

//选中item
private int selectitem;

//item选中回调接口
private oncarrouselitemselectedlistener moncarrouselitemselectedlistener;

//item点击回调接口
private oncarrouselitemclicklistener moncarrouselitemclicklistener;

//x轴旋转动画
private valueanimator xanimation;

//z轴旋转动画
private valueanimator zanimation;

private boolean isfinish = true;//惯性动画是否结束
private boolean isfling;

public carrousellayout(context context) {
this(context, null);
}

public carrousellayout(context context