首页 > 移动平台 > 详细

Android星球效果实现

时间:2018-10-16 17:06:02      阅读:405      评论:0      收藏:0      [点我收藏+]

技术分享图片

在项目中看着这个旋转效果挺炫的,就抽取出来做个记录。主要是使用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, 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;
}


}

Android星球效果实现

原文:https://www.cnblogs.com/lyfankai/p/9798653.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!