自定义3D效果的轮转控件

简介

近期项目中需要类似banner效果,但是又有一个点不一样,表达很生硬,直接看效果图如下。

未标题-1.gif

实现

通过效果图,要实现如上效果首先想到的是自定义控件,考虑到扩展我们要加入属性进行控制,自定义属性:展示方向、是否自动轮转等。 那么我们接下来就看如何实现。步骤分:

  1. 自定义属性
  2. 获取属性并初始化
  3. 实现手势及动画
  4. 调用

一、自定义属性

<resources>
    <attr name="myBackground" format="color" />
    <attr name="myTextColor" format="color" />

    <declare-styleable name="LoopRotarySwitchView">
        <attr name="orientation" format="integer">
            <enum name="vertical" value="0"/>
            <enum name="horizontal" value="1"/>
        </attr>
        <attr name="autoRotation" format="boolean"/>
        <attr name="r" format="dimension"/>

        <attr name="direction" format="integer">
            <enum name="left" value="0"/>
            <enum name="right" value="1"/>
        </attr>

    </declare-styleable>
</resources>

二、获取属性

public LoopRotarySwitchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        //获取自定义属性
        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.LoopRotarySwitchView);
        mOrientation=typedArray.getInt(R.styleable.LoopRotarySwitchView_orientation,horizontal);
        autoRotation=typedArray.getBoolean(R.styleable.LoopRotarySwitchView_autoRotation,false);
        r=typedArray.getDimension(R.styleable.LoopRotarySwitchView_r,LoopR);
        int direction=typedArray.getInt(R.styleable.LoopRotarySwitchView_direction,0);
        typedArray.recycle();
        //初始化手势
        mGestureDetector = new GestureDetector(context, getGeomeryController());
        //设置展示方向
        if(mOrientation==horizontal){//如果是水平 z值为0  如果是竖直z值为90
            loopRotationZ=0;
        }else{
            loopRotationZ=90;
        }
        if(direction==0){//设置自定滚动的方向
            autoRotatinDirection= AutoScrollDirection.left;
        }else{
            autoRotatinDirection= AutoScrollDirection.right;
        }
        loopHandler.setLoop(autoRotation);
    }

三、实现手势和动画

 /**
     * 手势
     *
     * @return
     */
    private GestureDetector.SimpleOnGestureListener getGeomeryController() {
        return new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                angle+=Math.cos(Math.toRadians(loopRotationZ))*(distanceX/views.size())
                        +Math.sin(Math.toRadians(loopRotationZ))*(distanceY/views.size());
                initView();
                return true;
            }
        };
    }

    private void initView() {
        for (int i = 0; i < views.size(); i++) {
            double radians=angle+180- i * 360 / size;
            float x0 = (float)Math.sin(Math.toRadians(radians)) * r;
            float y0 = (float)Math.cos(Math.toRadians(radians)) * r;
            float  scale0 = (distance - y0) / (distance + r);//计算子view之间的比例,可以看到distance越大的话 比例越小,也就是大小就相差越小
            views.get(i).setScaleX(scale0);//对view进行缩放
            views.get(i).setScaleY(scale0);//对view进行缩放
            float rotationX_y=(float)Math.sin(Math.toRadians(loopRotationX *Math.cos(Math.toRadians(radians))))*r;
            float rotationZ_y=-(float)Math.sin(Math.toRadians(-loopRotationZ))*x0;
            float rotationZ_x=(((float) Math.cos(Math.toRadians(-loopRotationZ))*x0)-x0);
            views.get(i).setTranslationX( x0 +rotationZ_x);
            views.get(i).setTranslationY(rotationX_y+rotationZ_y);
        }
        List<View> arrayViewList =new ArrayList<>();
        arrayViewList.clear();
        for (int i=0;i<views.size();i++){
            arrayViewList.add(views.get(i));
        }
        sortList(arrayViewList);
        postInvalidate();
    }

四、调用

调用和其他自定义控件一样,全路径名称然后设置属性。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.sunshine.rxjavademo.view.LoopRotarySwitchView
        android:id="@+id/loop_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"/>
</LinearLayout>
  private String[] titles = {"闹钟","实时监测","阿尔法"};
    private List<View> views = new ArrayList<>();
    private LoopRotarySwitchView loopRotarySwitchView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_more);
        initWidget();
        initData();
        initLoopRotarySwitchView();
    }

    private void initWidget() {
        loopRotarySwitchView = (LoopRotarySwitchView) findViewById(R.id.loop_view);
    }

    private void initData(){
        View view = LayoutInflater.from(this).inflate(R.layout.item_head_layout, null);
        View view1 = LayoutInflater.from(this).inflate(R.layout.item_head_layout, null);
        View view2 = LayoutInflater.from(this).inflate(R.layout.item_head_layout, null);
        views.add(view);
        views.add(view1);
        views.add(view2);
        for (int i=0;i<titles.length;i++){
            ((TextView) views.get(i).findViewById(R.id.tv_head)).setText(titles[i]);
            loopRotarySwitchView.addView(views.get(i));
        }
    }

    private void initLoopRotarySwitchView(){
        loopRotarySwitchView
                .setR(ScreenUtils.getScreenWidth(this)/1.8f)//设置R的大小
                .setAutoRotation(false)//是否自动切换
                .setAutoRotationTime(20000);//自动切换的时间  单位毫秒
        loopRotarySwitchView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(int item, View view) {
                ToastUtils.showMessage(titles[item]);
            }
        });
    }

最后放上整个自定义控件的代码

public class LoopRotarySwitchView extends RelativeLayout {

    private final static  int LoopR = 200;

    private final static  int  vertical=0;//竖直

    private final static  int  horizontal=1;//水平

    private  int mOrientation=horizontal;//方向

    private Context mContext;//上下文

    private ValueAnimator restAnimator = null;//回位动画

    private ValueAnimator rAnimation = null;//半径动画

    private ValueAnimator zAnimation=null;

    private ValueAnimator xAnimation=null;

    private int loopRotationX =0, loopRotationZ =0;//x轴旋转和轴旋转,y轴无效果

    private GestureDetector mGestureDetector = null;//手势类

    private int selectItem = 0;//当前选择项

    private int size = 0;//个数

    private float r = LoopR;//半径

    private float multiple = 2f;//倍数

    private float distance = multiple * r;//camera和观察的旋转物体距离, 距离越长,最大物体和最小物体比例越不明显

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

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

    private boolean autoRotation = false;//自动旋转

    private boolean touching = false;//正在触摸

    private AutoScrollDirection autoRotatinDirection = AutoScrollDirection.left; //默认自动滚动是从右往左

    private List<View> views = new ArrayList<View>();//子view引用列表

    private OnItemSelectedListener onItemSelectedListener = null;//选择事件接口

    private OnLoopViewTouchListener onLoopViewTouchListener = null;//选择事件接口

    private OnItemClickListener onItemClickListener = null;//被点击的回调

    private boolean isCanClickListener=true;//是否可以点击回调

    private float x;//移动的x是否符合回调点击事件

    private float limitX=30;//滑动倒最低30

    public enum AutoScrollDirection{
        left,right
    }
    /**
     * 构造方法
     *
     * @param context
     */
    public LoopRotarySwitchView(Context context) {
        this(context,null);
    }

    /**
     * 构造方法
     *
     * @param context
     * @param attrs
     */
    public LoopRotarySwitchView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    /**
     * 构造方法
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public LoopRotarySwitchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        //获取自定义属性
        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.LoopRotarySwitchView);
        mOrientation=typedArray.getInt(R.styleable.LoopRotarySwitchView_orientation,horizontal);
        autoRotation=typedArray.getBoolean(R.styleable.LoopRotarySwitchView_autoRotation,false);
        r=typedArray.getDimension(R.styleable.LoopRotarySwitchView_r,LoopR);
        int direction=typedArray.getInt(R.styleable.LoopRotarySwitchView_direction,0);
        typedArray.recycle();
        //初始化手势
        mGestureDetector = new GestureDetector(context, getGeomeryController());
        //设置展示方向
        if(mOrientation==horizontal){//如果是水平 z值为0  如果是竖直z值为90
            loopRotationZ=0;
        }else{
            loopRotationZ=90;
        }
        if(direction==0){//设置自定滚动的方向
            autoRotatinDirection= AutoScrollDirection.left;
        }else{
            autoRotatinDirection= AutoScrollDirection.right;
        }
        loopHandler.setLoop(autoRotation);
    }


    /**
     * handler处理
     */
    LoopRotarySwitchViewHandler loopHandler = new LoopRotarySwitchViewHandler(3000) {
        @Override
        public void doScroll() {
            try {
                if (size != 0) {//判断自动滑动从那边开始
                    int perAngle = 0;
                    switch (autoRotatinDirection)
                    {
                        case left:
                            perAngle = 360 /size;
                            break;
                        case right:
                            perAngle = -360/size;
                            break;
                    }
                    if (angle == 360) {
                        angle = 0f;
                    }
                    AnimRotationTo(angle + perAngle, null);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    /**
     * 排序
     * 對子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 lhs, View rhs) {
            int result = 0;
            try {
                result = (int) (1000 * lhs.getScaleX() - 1000 * rhs.getScaleX());
            } catch (Exception e) {
            }
            return result;
        }
    }

    /**
     * 手势
     *
     * @return
     */
    private GestureDetector.SimpleOnGestureListener getGeomeryController() {
        return new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                angle+=Math.cos(Math.toRadians(loopRotationZ))*(distanceX/views.size())
                        +Math.sin(Math.toRadians(loopRotationZ))*(distanceY/views.size());
                initView();
                return true;
            }
        };
    }

    private void initView() {
        for (int i = 0; i < views.size(); i++) {
            double radians=angle+180- i * 360 / size;
            float x0 = (float)Math.sin(Math.toRadians(radians)) * r;
            float y0 = (float)Math.cos(Math.toRadians(radians)) * r;
            float  scale0 = (distance - y0) / (distance + r);//计算子view之间的比例,可以看到distance越大的话 比例越小,也就是大小就相差越小
            views.get(i).setScaleX(scale0);//对view进行缩放
            views.get(i).setScaleY(scale0);//对view进行缩放
            float rotationX_y=(float)Math.sin(Math.toRadians(loopRotationX *Math.cos(Math.toRadians(radians))))*r;
            float rotationZ_y=-(float)Math.sin(Math.toRadians(-loopRotationZ))*x0;
            float rotationZ_x=(((float) Math.cos(Math.toRadians(-loopRotationZ))*x0)-x0);
            views.get(i).setTranslationX( x0 +rotationZ_x);
            views.get(i).setTranslationY(rotationX_y+rotationZ_y);
        }
        List<View> arrayViewList =new ArrayList<>();
        arrayViewList.clear();
        for (int i=0;i<views.size();i++){
            arrayViewList.add(views.get(i));
        }
        sortList(arrayViewList);
        postInvalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        initView();
        if (autoRotation) {
            loopHandler.sendEmptyMessageDelayed(LoopRotarySwitchViewHandler.msgid, loopHandler.loopTime);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed) {
            checkChildView();
            if (onItemSelectedListener != null) {
                isCanClickListener = true;
                onItemSelectedListener.selected(selectItem, views.get(selectItem));
            }
            RAnimation();
        }
    }

    public void RAnimation() {
        RAnimation(1f, r);
    }

    public void RAnimation(boolean fromZeroToLoopR) {
        if (fromZeroToLoopR) {
            RAnimation(1f, LoopR);
        } else {
            RAnimation(LoopR, 1f);
        }
    }

    public void RAnimation(float from, float to) {
        rAnimation = ValueAnimator.ofFloat(from, to);
        rAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                r = (Float) valueAnimator.getAnimatedValue();
                initView();
            }
        });
        rAnimation.setInterpolator(new DecelerateInterpolator());
        rAnimation.setDuration(2000);
        rAnimation.start();
    }


    /**
     * 初始化view
     */
    public void checkChildView(){
        for (int i = 0; i < views.size(); i++) {//先清空views里边可能存在的view防止重复
            views.remove(i);
        }
        final int count = getChildCount(); //获取子View的个数
        size = count;

        for (int i = 0; i < count; i++) {
            View view = getChildAt(i); //获取指定的子view
            final int position = i;
            views.add(view);
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    //对子view添加点击事件
//                    if (position != calculateItem()) {
//                        setSelectItem(position);
//                    }else {
                        if (isCanClickListener && onItemClickListener != null) {
                            onItemClickListener.onItemClick(position, views.get(position));
                        }
//                    }
                }
            });

        }

    }
    /**
     * 复位
     */
    private void restPosition() {
        if (size == 0) {
            return;
        }
        float finall = 0;
        float part = 360 / size;//一份的角度
        if (angle < 0) {
            part = -part;
        }
        float minvalue = (int) (angle / part) * part;//最小角度
        float maxvalue = (int) (angle / part) * part + part;//最大角度
        if (angle >= 0) {//分为是否小于0的情况
            if (angle - last_angle > 0) {
                finall = maxvalue;
            } else {
                finall = minvalue;
            }
        } else {
            if (angle - last_angle < 0) {
                finall = maxvalue;
            } else {
                finall = minvalue;
            }
        }
        AnimRotationTo(finall, null);
    }


    /**
     * 动画
     *
     * @param finall
     * @param complete
     */
    private void AnimRotationTo(float finall, final Runnable complete) {
        if (angle == finall) {//如果相同说明不需要旋转
            return;
        }
        restAnimator = ValueAnimator.ofFloat(angle, finall);
        restAnimator.setInterpolator(new DecelerateInterpolator());//设置旋转减速插值器
        restAnimator.setDuration(300);

        restAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (touching == false) {
                    angle = (Float) animation.getAnimatedValue();
                    initView();
                }
            }
        });
        restAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (touching == false) {
                    selectItem = calculateItem();
                    if (selectItem < 0) {
                        selectItem = size + selectItem;
                    }
                    if (onItemSelectedListener != null) {
                        onItemSelectedListener.selected(selectItem, views.get(selectItem));
                    }
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        if (complete != null) {
            restAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    complete.run();
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
        }
        restAnimator.start();
    }

    /**
     * 通过角度计算是第几个item
     *
     * @return
     */
    private int calculateItem() {
        return Math.abs((int) (angle / (360 / size)) % size);
    }

    /**
     * 触摸操作
     *
     * @param event
     * @return
     */
    private boolean onTouch(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            last_angle = angle;
            touching = true;
        }
        boolean sc = mGestureDetector.onTouchEvent(event);
        if (sc) {
            this.getParent().requestDisallowInterceptTouchEvent(true);//通知父控件勿拦截本控件
        }
        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
            touching = false;
            restPosition();
            return true;
        }
        return true;
    }


    /**
     * 触摸方法
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (onLoopViewTouchListener != null) {
            onLoopViewTouchListener.onTouch(event);
        }
        isCanClickListener(event);
        return true;
    }


    /**
     * 触摸停止计时器,抬起设置可下啦刷新
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        onTouch(ev);
        if (onLoopViewTouchListener != null) {
            onLoopViewTouchListener.onTouch(ev);
        }
        isCanClickListener(ev);
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 是否可以点击回调
     * @param event
     */
    public void  isCanClickListener(MotionEvent event){
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                x = event.getX();
                if (autoRotation) {
                    loopHandler.removeMessages(LoopRotarySwitchViewHandler.msgid);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (autoRotation) {
                    loopHandler.sendEmptyMessageDelayed(LoopRotarySwitchViewHandler.msgid,  loopHandler.loopTime);
                }
                if (event.getX() - x > limitX || x - event.getX() > limitX) {
                    isCanClickListener = false;
                } else {
                    isCanClickListener = true;
                }
                break;
        }
    }
    /**
     * 获取所有的view
     *
     * @return
     */
    public List<View> getViews() {
        return views;
    }

    /**
     * 获取角度
     *
     * @return
     */
    public float getAngle() {
        return angle;
    }


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

    /**
     * 获取距离
     *
     * @return
     */
    public float getDistance() {
        return distance;
    }

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

    /**
     * 获取半径
     *
     * @return
     */
    public float getR() {
        return r;
    }

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

    /**
     * 设置选中方法
     *
     * @param selectItem
     */
    public void setSelectItem(int selectItem) {

        if (selectItem >= 0) {
            float jiaodu = 0;
            if (getSelectItem() == 0) {
                if (selectItem == views.size() - 1) {
                    jiaodu = angle - (360 / size);
                } else {
                    jiaodu = angle + (360 / size);
                }
            } else if (getSelectItem() == views.size() - 1) {
                if (selectItem == 0) {
                    jiaodu = angle + (360 / size);
                } else {
                    jiaodu = angle - (360 / size);
                }
            } else {
                if (selectItem > getSelectItem()) {
                    jiaodu = angle + (360 / size);
                } else {
                    jiaodu = angle - (360 / size);
                }
            }

            float finall = 0;
            float part = 360 / size;//一份的角度
            if (jiaodu < 0) {
                part = -part;
            }
            float minvalue = (int) (jiaodu / part) * part;//最小角度
            float maxvalue = (int) (jiaodu / part) * part;//最大角度
            if (jiaodu >= 0) {//分为是否小于0的情况
                if (jiaodu - last_angle > 0) {
                    finall = maxvalue;
                } else {
                    finall = minvalue;
                }
            } else {
                if (jiaodu - last_angle < 0) {
                    finall = maxvalue;
                } else {
                    finall = minvalue;
                }
            }

            if (size > 0) AnimRotationTo(finall, null);
        }
    }

    /**
     * 设置半径
     *
     * @param r
     */
    public LoopRotarySwitchView setR(float r) {
        this.r = r;
        distance = multiple * r;
        return  this;
    }

    /**
     * 选中回调接口实现
     *
     * @param onItemSelectedListener
     */
    public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
        this.onItemSelectedListener = onItemSelectedListener;
    }

    /**
     * 点击事件回调
     *
     * @param onItemClickListener
     */
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    /**
     * 触摸时间回调
     *
     * @param onLoopViewTouchListener
     */
    public void setOnLoopViewTouchListener(OnLoopViewTouchListener onLoopViewTouchListener) {
        this.onLoopViewTouchListener = onLoopViewTouchListener;
    }

    /**
     * 设置是否自动切换
     *
     * @param autoRotation
     */
    public LoopRotarySwitchView setAutoRotation(boolean autoRotation) {
        this.autoRotation = autoRotation;
        loopHandler.setLoop(autoRotation);
        return this;
    }

    /**
     * 获取自动切换时间
     *
     * @return
     */
    public long getAutoRotationTime() {
        return loopHandler.loopTime;
    }

    /**
     * 设置自动切换时间间隔
     *
     * @param autoRotationTime
     */
    public LoopRotarySwitchView setAutoRotationTime(long autoRotationTime) {
        loopHandler.setLoopTime(autoRotationTime);
        return this;
    }

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

    /**
     * 设置倍数
     *
     * @param mMultiple 设置这个必须在setR之前调用,否则无效
     * @return
     */
    public LoopRotarySwitchView setMultiple(float mMultiple) {
        this.multiple = mMultiple;
        return this;
    }

    public LoopRotarySwitchView setAutoScrollDirection(AutoScrollDirection mAutoScrollDirection) {
        this.autoRotatinDirection = mAutoScrollDirection;
        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) {
                loopRotationX= (Integer) animation.getAnimatedValue();
                initView();
            }
        });
        xAnimation.setInterpolator(new DecelerateInterpolator());
        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) {
                loopRotationZ= (Integer) animation.getAnimatedValue();
                initView();
            }
        });
        zAnimation.setInterpolator(new DecelerateInterpolator());
        zAnimation.setDuration(2000);
        if(start)zAnimation.start();
        return zAnimation;
    }

    /**
     * 设置方向
     * @param mOrientation
     * @return
     */
    public   LoopRotarySwitchView setOrientation(int mOrientation){
        setHorizontal(mOrientation==horizontal,false);
        return this;
    }
    public LoopRotarySwitchView setHorizontal(boolean horizontal,boolean anim) {
        if(anim){
            if(horizontal){
                createZAnimation(getLoopRotationZ(),0,true);
            }else{
                createZAnimation(getLoopRotationZ(),90,true);
            }
        }else{
            if(horizontal){
                setLoopRotationZ(0);
            }else {
                setLoopRotationZ(90);
            }
            initView();
        }
        return  this;
    }

    public LoopRotarySwitchView setLoopRotationX(int loopRotationX) {
        this.loopRotationX = loopRotationX;
        return this;
    }

    public LoopRotarySwitchView setLoopRotationZ(int loopRotationZ) {
        this.loopRotationZ = loopRotationZ;
        return this;
    }

    public int getLoopRotationX() {
        return loopRotationX;
    }

    public int getLoopRotationZ() {
        return loopRotationZ;
    }

    public ValueAnimator getRestAnimator() {
        return restAnimator;
    }

    public ValueAnimator getrAnimation() {
        return rAnimation;
    }

    public void setzAnimation(ValueAnimator zAnimation) {
        this.zAnimation = zAnimation;
    }

    public ValueAnimator getzAnimation() {
        return zAnimation;
    }

    public void setxAnimation(ValueAnimator xAnimation) {
        this.xAnimation = xAnimation;
    }

    public ValueAnimator getxAnimation() {
        return xAnimation;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,918评论 25 707
  • 橄欖油炸花生米 豆豉鯪魚油麥菜 韭黃炒五花肉 海米黃瓜條 米湯蘿蔔絲 素炒肉蘑 正宗燉羊排
    叁壹柒阅读 297评论 0 0
  • 最近我发现自己在交朋友方面越来越懒,有的时候明知道你是个很温和很nice的人,可就是不肯主动和别人互动,遇到问题也...
    猫眼童鞋阅读 317评论 0 0
  • 夏目祐太阅读 4,482评论 23 144
  • 文/鹿暖 1 我认识个姑娘,特别好的闺蜜,让人觉得又爱又恨的一个女子,称她为Z。 Z是个典型的极端主义者,情绪永远...
    鹿暖阅读 511评论 0 2