在项目中看着这个旋转效果挺炫的,就抽取出来做个记录。主要是使用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 = ; //旋转木马子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, );
} 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, );
mCarrouselR = typedArray.getDimension(R.styleable.CarrouselLayout_r, );
mRotateDirection = typedArray.getInt(R.styleable.CarrouselLayout_rotateDirection, );
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 != ) {//判断自动滑动从那边开始
int perAngle = ;
switch (rotateDirection) {
case clockwise:
perAngle = 360 / viewCount;
break;
case anticlockwise:
perAngle = -360 / viewCount;
break;
}
if (mAngle == ) {
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() < ) { // 左滑
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 > ) { // 左滑
setAutoScrollDirection(CarrouselRotateDirection.clockwise);
} else {
setAutoScrollDirection(CarrouselRotateDirection.anticlockwise);
}
//转换成弧度
double radians = Math.toRadians(mRotationZ);
//Math.cos(radians) 返回对应的radians弧度的余弦值
mAngle += Math.cos(radians) * (distanceX / ) + Math.sin(radians) * (distanceY / );
// Log.e("mAngle", mAngle + "");
Log.e("mRotationZ", mRotationZ + "");
//初始化
refreshLayout();
return true;
} };
} /**
* 初始化 计算平均角度后各个子view的位置
*/
public void refreshLayout() {
for (int i = ; 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() >= ) {
if (((RelativeLayout) mCarrouselViews.get(i)).getChildAt() instanceof ImageView) {
int value = Float.valueOf((scale0 < 0.5f ? 0.5f : scale0) * ).intValue();
((ImageView) ((RelativeLayout) mCarrouselViews.get(i)).getChildAt()).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() instanceof TextView) {
((RelativeLayout) mCarrouselViews.get(i)).getChildAt().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 = ; 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 = ;
ListIterator<T> it = (ListIterator<T>) list.listIterator();
while (it.hasNext()) {
it.next();
it.set(array[i++]);
}
for (int j = ; 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();
mAnimationR.start();
} public void checkChildView() {
//先清空views里边可能存在的view防止重复
for (int i = ; i < mCarrouselViews.size(); i++) {
mCarrouselViews.remove(i);
}
final int count = getChildCount(); //获取子View的个数
viewCount = count;
for (int i = ; 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 == ) {
return;
}
float resultAngle = ;
//平均角度
float averageAngle = 360 / viewCount;
if (mAngle < ) {
averageAngle = -averageAngle;
}
float minvalue = (int) (mAngle / averageAngle) * averageAngle;//最小角度
float maxvalue = (int) (mAngle / averageAngle) * averageAngle + averageAngle;//最大角度
if (mAngle >= ) {//分为是否小于0的情况
if (mAngle - mLastAngle > ) {
resultAngle = maxvalue;
} else {
resultAngle = minvalue;
}
} else {
if (mAngle - mLastAngle < ) {
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) * );
//设置旋转匀速插值器
restAnimator.setInterpolator(new DecelerateInterpolator());
restAnimator.setDuration();
} else {
restAnimator = ValueAnimator.ofFloat(mAngle, resultAngle);
//设置旋转匀速插值器
restAnimator.setInterpolator(new LinearInterpolator());
restAnimator.setDuration();
} 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 < ) {
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 = ;
float DownY = ;
long currentMS = ; 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 > ) {
isTouching = true;
isfinish = true; stopAutoRotation();
} break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (Math.abs(moveX) > 50 && moveTime > ) {
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, );
}
} /**
* 获取所有的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 >= ) {
float angle = ;
if (getSelectItem() == ) {
if (selectItem == mCarrouselViews.size() - ) {
angle = mAngle - (360 / viewCount);
} else {
angle = mAngle + (360 / viewCount);
}
} else if (getSelectItem() == mCarrouselViews.size() - ) {
if (selectItem == ) {
angle = mAngle + (360 / viewCount);
} else {
angle = mAngle - (360 / viewCount);
}
} else {
if (selectItem > getSelectItem()) {
angle = mAngle + (360 / viewCount);
} else {
angle = mAngle - (360 / viewCount);
}
} float resultAngle = ;
float part = 360 / viewCount;
if (angle < ) {
part = -part;
}
//最小角度
float minvalue = (int) (angle / part) * part;
Log.e("minvalue", minvalue + "");
//最大角度
float maxvalue = (int) (angle / part) * part; if (angle >= ) {//分为是否小于0的情况
if (angle - mLastAngle > ) {
resultAngle = maxvalue;
Log.e("maxvalue", resultAngle + "");
} else {
resultAngle = minvalue;
Log.e("maxvalue", resultAngle + "");
}
} else {
if (angle - mLastAngle < ) {
resultAngle = maxvalue;
} else {
resultAngle = minvalue;
}
} if (viewCount > ) 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();
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();
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;
} }

最新文章

  1. iOS开发之ReactiveCocoa下的MVVM(干货分享)
  2. node.js整理 04网络操作
  3. JS正则表达式验证数字(很全)
  4. Apache common pool2 对象池
  5. new,delete和malloc,free以及allocator&lt;T&gt;
  6. MallBuilder 多用户商城管理系统 v5.8.1.1
  7. RHEL6.3 ftp服务器参数的戏说——不看白不看,看了不白看
  8. 调用百度地图API实现手机自动定位 (逆地址解析)
  9. Linux BFS简介
  10. winform 实现选择的城市名单
  11. MCMC(四)Gibbs采样
  12. jsoup从表单中取数据
  13. 读书笔记---HTML5实战 MARCO CASARIO(后六章)
  14. HTTP状态码的详细解释,供参考
  15. C# 实体转为json字符串
  16. 【leetcode】13-Roman2Integer
  17. Spring学习笔记三:Bean管理
  18. [OpenGL]用OpenGL制作动画
  19. mac 10.13 build 一个 redis desktop manager
  20. Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

热门文章

  1. 签名时出错: 未在路径 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin
  2. python(leetcode)-重复元素算法题
  3. [原创]K8Cscan插件之Cisco思科设备扫描(IP、设备型号、主机名、Boot、硬件版本)
  4. 解决关于 ionic3 启动白屏 控制台错误提示:Uncaught SyntaxError Use of const in strict mode.
  5. sql server 备份与恢复系列四 大容量模式下的备份与还原
  6. Java集合及concurrent并发包总结(转)
  7. Android内存优化之内存缓存
  8. 使用IntelliJ IDEA新建Java Web后端resfulAPI模板
  9. Windows 上的 SSH?使用 PowerShell Remoting 远程管理 Windows 服务器
  10. 【原创】Python第二章——行与缩进