【特效】3D旋转环形菜单

主页面的xml文件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:id="@+id/layout_next"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/user_wizard_2"
        android:orientation="vertical" />

    <LinearLayout
        android:id="@+id/layout_last"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/user_wizard_3"
        android:orientation="vertical" />

    <RelativeLayout
        android:id="@+id/layout_main"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@drawable/user_wizard_1"
        android:orientation="vertical" >

        <include layout="@layout/bottom_button" />
    </RelativeLayout>

</FrameLayout>
View Code

点击Hone按钮弹出菜单xml文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <RelativeLayout
        android:id="@+id/composer_buttons_wrapper"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:clipChildren="false"
        android:clipToPadding="false" >

        <ImageButton
            android:id="@+id/composer_button_photo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="142dp"
            android:layout_marginRight="10.667dp"
            android:background="@drawable/composer_camera"
            android:visibility="gone" />

        <ImageButton
            android:id="@+id/composer_button_people"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="135.333dp"
            android:layout_marginRight="52dp"
            android:background="@drawable/composer_with"
            android:visibility="gone" />

        <ImageButton
            android:id="@+id/composer_button_place"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="116.666dp"
            android:layout_marginRight="89.33333333333333dp"
            android:background="@drawable/composer_place"
            android:visibility="gone" />

        <ImageButton
            android:id="@+id/composer_button_music"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="87.33333333333333dp"
            android:layout_marginRight="118.6666666666667dp"
            android:background="@drawable/composer_music"
            android:visibility="gone" />

        <ImageButton
            android:id="@+id/composer_button_thought"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="50dp"
            android:layout_marginRight="137.3333333333333dp"
            android:background="@drawable/composer_thought"
            android:visibility="gone" />

        <ImageButton
            android:id="@+id/composer_button_sleep"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="8.666666666666667dp"
            android:layout_marginRight="144dp"
            android:background="@drawable/composer_sleep"
            android:visibility="gone" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/composer_buttons_show_hide_button"
        android:layout_width="60dp"
        android:layout_height="57.33333333333333dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:background="@drawable/composer_button" >

        <ImageView
            android:id="@+id/composer_buttons_show_hide_button_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/composer_icn_plus" />
    </RelativeLayout>

</RelativeLayout>
View Code

主Activity页面

package cy.test.rotate3d;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class RotateActivity extends Activity implements OnTouchListener {
    public final static int TYPE_ROTATING = 0;
    public final static int TYPE_ENDROTATE = 1;
    public final static int TYPE_VELROTATE = 2;
    public static float params = 1;
    private ViewGroup layoutmain;
    private ViewGroup layoutnext;
    private ViewGroup layoutlast;

    private ViewGroup currentView;
    private ViewGroup nextView;
    private ViewGroup lastView;

    private Rotate3D rotate3d;
    private Rotate3D rotate3d2;
    private Rotate3D rotate3d3;
    private int mCenterX;
    private int mCenterY;
    private float degree = (float) 0.0;
    private int currentTab = 0;
    private float perDegree;
    private VelocityTracker mVelocityTracker;

    private boolean areButtonsShowing;
    private RelativeLayout composerButtonsWrapper;
    private ImageView composerButtonsShowHideButtonIcon;
    private RelativeLayout composerButtonsShowHideButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initMain();
        MyAnimations.initOffset(this);

        // 加号的动画
        composerButtonsShowHideButton.startAnimation(MyAnimations
                .getRotateAnimation(0, 360, 200));
        DisplayMetrics dm = new DisplayMetrics();
        dm = getResources().getDisplayMetrics();
        mCenterX = dm.widthPixels / 2;
        mCenterY = dm.heightPixels / 2;
        if (dm.widthPixels > 320) {
            params = 2.0f / 3;
        }
        perDegree = (float) (90.0 / dm.widthPixels);
    }

    private void setListener() {
        // 给大按钮设置点击事件
        composerButtonsShowHideButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (!areButtonsShowing) {
                    // 图标的动画
                    MyAnimations.startAnimationsIn(composerButtonsWrapper, 300);
                    // 加号的动画
                    composerButtonsShowHideButtonIcon
                            .startAnimation(MyAnimations.getRotateAnimation(0,
                                    -225, 300));
                } else {
                    // 图标的动画
                    MyAnimations
                            .startAnimationsOut(composerButtonsWrapper, 300);
                    // 加号的动画
                    composerButtonsShowHideButtonIcon
                            .startAnimation(MyAnimations.getRotateAnimation(
                                    -225, 0, 300));
                }
                areButtonsShowing = !areButtonsShowing;
            }
        });

        // 给小图标设置点击事件
        for (int i = 0; i < composerButtonsWrapper.getChildCount(); i++) {
            final ImageView smallIcon = (ImageView) composerButtonsWrapper
                    .getChildAt(i);
            final int position = i;
            smallIcon.setOnClickListener(new View.OnClickListener() {
                public void onClick(View arg0) {
                    // 这里写各个item的点击事件
                    // 1.加号按钮缩小后消失 缩小的animation
                    // 2.其他按钮缩小后消失 缩小的animation
                    // 3.被点击按钮放大后消失 透明度渐变 放大渐变的animation
                    // composerButtonsShowHideButton.startAnimation(MyAnimations.getMiniAnimation(300));
                    if (areButtonsShowing) {
                        composerButtonsShowHideButtonIcon
                                .startAnimation(MyAnimations
                                        .getRotateAnimation(-225, 0, 300));
                        smallIcon.startAnimation(MyAnimations
                                .getMaxAnimation(400));
                        for (int j = 0; j < composerButtonsWrapper
                                .getChildCount(); j++) {
                            if (j != position) {
                                final ImageView smallIcon = (ImageView) composerButtonsWrapper
                                        .getChildAt(j);
                                smallIcon.startAnimation(MyAnimations
                                        .getMiniAnimation(300));
                                // MyAnimations.getMiniAnimation(300).setFillAfter(true);
                            }
                        }
                        areButtonsShowing = !areButtonsShowing;
                    }

                }
            });
        }
    }

    private void initMain() {
        setContentView(R.layout.main);

        composerButtonsWrapper = (RelativeLayout) findViewById(R.id.composer_buttons_wrapper);
        composerButtonsShowHideButton = (RelativeLayout) findViewById(R.id.composer_buttons_show_hide_button);
        composerButtonsShowHideButtonIcon = (ImageView) findViewById(R.id.composer_buttons_show_hide_button_icon);

        layoutnext = (ViewGroup) findViewById(R.id.layout_next);
        layoutnext.setOnTouchListener(this);

        layoutlast = (ViewGroup) findViewById(R.id.layout_last);
        layoutlast.setOnTouchListener(this);

        layoutmain = (ViewGroup) findViewById(R.id.layout_main);
        layoutmain.setOnTouchListener(this);
        setListener();

        currentView = layoutmain;
        nextView = layoutnext;
        lastView = layoutnext;
    }

    private int mLastMotionX;

    public boolean onTouch(View arg0, MotionEvent event) {
        int x = (int) event.getX();
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();// 获得VelocityTracker类实例
        }
        mVelocityTracker.addMovement(event);// 将事件加入到VelocityTracker类实例中
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mLastMotionX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            mVelocityTracker.computeCurrentVelocity(1000, 1000);
            int dx = x - mLastMotionX;
            if (dx != 0) {
                doRotate(dx, TYPE_ROTATING);
                if (degree > 90) {
                    degree = 0;
                    break;
                }
            } else {
                return false;
            }
            mLastMotionX = x;
            break;
        case MotionEvent.ACTION_UP:
            // 设置units的值为1000,意思为一秒时间内运动了多少个像素
            mVelocityTracker.computeCurrentVelocity(1000);
            float VelocityX = mVelocityTracker.getXVelocity();
            if (VelocityX > 500 || VelocityX < -500) {
                // endRotateByVelocity();
                doRotate(0, TYPE_VELROTATE);
            } else {
                // endRotate();
                doRotate(0, TYPE_ENDROTATE);
            }
            setView();
            setViewVisibile();
            degree = 0;

            releaseVelocityTracker();
            break;

        case MotionEvent.ACTION_CANCEL:
            releaseVelocityTracker();
            break;
        }
        return true;
    }

    private void setView() {
        if (currentTab == 0) {
            currentView = layoutmain;
            nextView = layoutnext;
            lastView = layoutlast;
        } else if (currentTab == 1) {
            currentView = layoutnext;
            nextView = layoutlast;
            lastView = layoutmain;
        } else if (currentTab == 2) {
            currentView = layoutlast;
            nextView = layoutmain;
            lastView = layoutnext;
        }
    }

    private void releaseVelocityTracker() {
        if (null != mVelocityTracker) {
            mVelocityTracker.clear();
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }

    }

    private void setViewVisibile() {
        if (currentTab == 0) {
            layoutmain.setVisibility(View.VISIBLE);
            layoutnext.setVisibility(View.GONE);
            layoutlast.setVisibility(View.GONE);
        } else if (currentTab == 1) {
            layoutmain.setVisibility(View.GONE);
            layoutnext.setVisibility(View.VISIBLE);
            layoutlast.setVisibility(View.GONE);
        } else if (currentTab == 2) {
            layoutmain.setVisibility(View.GONE);
            layoutnext.setVisibility(View.GONE);
            layoutlast.setVisibility(View.VISIBLE);
        }
    }

    private void doRotate(int dx, int type) {
        if (type == TYPE_ROTATING) {
            float xd = degree;
            degree += perDegree * dx;
            rotate3d = new Rotate3D(xd, degree, 0, mCenterX, mCenterY);
            rotate3d2 = new Rotate3D(90 + xd, 90 + degree, 0, mCenterX,
                    mCenterY);
            rotate3d3 = new Rotate3D(-90 + xd, -90 + degree, 0, mCenterX,
                    mCenterY);
        } else if (type == TYPE_ENDROTATE) {
            rotate3d2 = new Rotate3D(90 + degree, 0, 0, mCenterX, mCenterY);
            rotate3d3 = new Rotate3D(-90 + degree, 0, 0, mCenterX, mCenterY);
            if (degree > 45) {
                rotate3d = new Rotate3D(degree, 90, 0, mCenterX, mCenterY);
                currentTab = (currentTab - 1) % 3;
                if (currentTab < 0) {
                    currentTab = 2;
                }
            } else if (degree < -45) {
                rotate3d = new Rotate3D(degree, -90, 0, mCenterX, mCenterY);
                currentTab = (currentTab + 1) % 3;
            } else {
                rotate3d = new Rotate3D(degree, 0, 0, mCenterX, mCenterY);
                rotate3d2 = new Rotate3D(90 + degree, 90, 0, mCenterX, mCenterY);
                rotate3d3 = new Rotate3D(-90 + degree, -90, 0, mCenterX,
                        mCenterY);
            }

        } else if (type == TYPE_VELROTATE) {
            if (degree > 0) {
                rotate3d = new Rotate3D(degree, 90, 0, mCenterX, mCenterY);
                rotate3d3 = new Rotate3D(-90 + degree, 0, 0, mCenterX, mCenterY);
                currentTab = (currentTab - 1) % 3;
                if (currentTab < 0) {
                    currentTab = 2;
                }
            } else if (degree < 0) {
                rotate3d = new Rotate3D(degree, -90, 0, mCenterX, mCenterY);
                rotate3d2 = new Rotate3D(90 + degree, 0, 0, mCenterX, mCenterY);
                currentTab = (currentTab + 1) % 3;
            }

        }
        rotate3d.setDuration(300);
        rotate3d2.setDuration(300);
        rotate3d3.setDuration(300);

        layoutmain.setVisibility(View.GONE);
        layoutnext.setVisibility(View.GONE);
        layoutlast.setVisibility(View.GONE);

        currentView.setVisibility(View.VISIBLE);
        if (degree < 0) {// 由右向左滑
            nextView.setVisibility(View.VISIBLE);
            toDoAnimation(currentView, rotate3d, Rotate3D.BOUNDARY_RIGHT);
            toDoAnimation(nextView, rotate3d2, Rotate3D.BOUNDARY_LEFT);
        } else if (degree > 0) {
            lastView.setVisibility(View.VISIBLE);
            toDoAnimation(currentView, rotate3d, Rotate3D.BOUNDARY_LEFT);
            toDoAnimation(lastView, rotate3d3, Rotate3D.BOUNDARY_RIGHT);
        }

    }

    public void toDoAnimation(ViewGroup viewGroup, Rotate3D rotate3d, int type) {
        rotate3d.setType(type);
        viewGroup.startAnimation(rotate3d);

    }
}
View Code

Rotate3D.java

package cy.test.rotate3d;

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.Transformation;

public class Rotate3D extends Animation {
    public final static int BOUNDARY_LEFT = 0;
    public final static int BOUNDARY_RIGHT = 1;

    private int type;
    private float fromDegree; // 旋转起始角度
    private float toDegree; // 旋转终止角度
    private float mCenterX; // 旋转中心x
    private float mCenterY; // 旋转中心y
    private Camera mCamera;

    public void setType(int type) {
        this.type = type;

    }

    public Rotate3D(float fromDegree, float toDegree, float depthZ,
            float centerX, float centerY) {
        this.fromDegree = fromDegree;
        this.toDegree = toDegree;
        this.mCenterX = centerX;
        this.mCenterY = centerY;
    }

    public Rotate3D(float fromDegree, float toDegree, float depthZ,
            float centerX, float centerY, int type) {
        this.fromDegree = fromDegree;
        this.toDegree = toDegree;
        this.mCenterX = centerX;
        this.mCenterY = centerY;
        this.type = type;
    }

    @Override
    public void initialize(int width, int height, int parentWidth,
            int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float FromDegree = fromDegree;
        // 旋转角度(angle)
        float degrees = FromDegree + (toDegree - fromDegree) * interpolatedTime; 
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Matrix matrix = t.getMatrix();

        if (degrees <= -79.5f) {
            degrees = -90.0f;
            mCamera.save();
            mCamera.rotateY(degrees); // 旋转
            mCamera.getMatrix(matrix);
            mCamera.restore();
        } else if (degrees >= 79.5f) {
            degrees = 90.0f;
            mCamera.save();
            mCamera.rotateY(degrees);
            mCamera.getMatrix(matrix);
            mCamera.restore();
        } else {
            mCamera.save();
            mCamera.translate(degrees / 90 * centerX * 2, 0, 0);
            mCamera.rotateY(degrees * RotateActivity.params);
            // mCamera.translate(0, 0, centerX); // 位移x
            // mCamera.rotateY(degrees);
            // mCamera.translate(0, 0, -centerX);
            mCamera.getMatrix(matrix);
            mCamera.restore();
        }

        if (type == BOUNDARY_LEFT) {
            matrix.preTranslate(0, -centerY);
            matrix.postTranslate(0, centerY);
        } else {
            matrix.preTranslate(-centerX * 2, -centerY);
            matrix.postTranslate(centerX * 2, centerY);
        }

    }
}
View Code

MyAnimations.java

package cy.test.rotate3d;

import android.content.Context;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;

public class MyAnimations {

    // 用来适配不同的分辨率
    private static int xOffset = 15;
    private static int yOffset = -13;

    public static void initOffset(Context context) {
        xOffset = (int) (10.667 * context.getResources().getDisplayMetrics().density);
        yOffset = -(int) (8.667 * context.getResources().getDisplayMetrics().density);
    }

    // 加号的动画
    public static Animation getRotateAnimation(float fromDegrees,
            float toDegrees, int durationMillis) {
        RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        rotate.setDuration(durationMillis);
        rotate.setFillAfter(true);
        return rotate;
    }

    // 图标的动画(入动画)
    public static void startAnimationsIn(ViewGroup viewgroup, int durationMillis) {
        for (int i = 0; i < viewgroup.getChildCount(); i++) {
            ImageButton inoutimagebutton = (ImageButton) viewgroup
                    .getChildAt(i);
            inoutimagebutton.setVisibility(0);
            inoutimagebutton.setClickable(true);
            inoutimagebutton.setFocusable(true);
            MarginLayoutParams mlp = (MarginLayoutParams) inoutimagebutton
                    .getLayoutParams();
            Animation animation = new TranslateAnimation(mlp.rightMargin
                    - xOffset, 0F, yOffset + mlp.bottomMargin, 0F);

            animation.setFillAfter(true);
            animation.setDuration(durationMillis);
            // 下一个动画的偏移时间
            animation.setStartOffset((i * 100)
                    / (-1 + viewgroup.getChildCount()));
            // 动画的效果
            animation.setInterpolator(new OvershootInterpolator(2F));
            // 弹出再回来的效果
            inoutimagebutton.startAnimation(animation);

        }
    }

    // 图标的动画(出动画)
    public static void startAnimationsOut(ViewGroup viewgroup,
            int durationMillis) {
        for (int i = 0; i < viewgroup.getChildCount(); i++) {
            final ImageButton inoutimagebutton = (ImageButton) viewgroup
                    .getChildAt(i);
            MarginLayoutParams mlp = (MarginLayoutParams) inoutimagebutton
                    .getLayoutParams();
            Animation animation = new TranslateAnimation(0F, mlp.rightMargin
                    - xOffset, 0F, yOffset + mlp.bottomMargin);

            animation.setFillAfter(true);
            animation.setDuration(durationMillis);
            animation.setStartOffset(((viewgroup.getChildCount() - i) * 100)
                    / (-1 + viewgroup.getChildCount()));// 下一个动画的偏移时间
            animation.setAnimationListener(new Animation.AnimationListener() {
                public void onAnimationStart(Animation arg0) {
                }

                public void onAnimationRepeat(Animation arg0) {
                }

                public void onAnimationEnd(Animation arg0) {
                    inoutimagebutton.setVisibility(8);
                    inoutimagebutton.setClickable(false);
                    inoutimagebutton.setFocusable(false);
                }
            });
            inoutimagebutton.startAnimation(animation);
        }
    }

    // icon缩小消失的动画
    public static Animation getMiniAnimation(int durationMillis) {
        Animation miniAnimation = new ScaleAnimation(1.0f, 0f, 1.0f, 0f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        miniAnimation.setDuration(durationMillis);
        miniAnimation.setFillAfter(true);
        return miniAnimation;
    }

    // icon放大渐变消失的动画
    public static Animation getMaxAnimation(int durationMillis) {
        AnimationSet animationset = new AnimationSet(true);

        Animation maxAnimation = new ScaleAnimation(1.0f, 4.0f, 1.0f, 4.0f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        Animation alphaAnimation = new AlphaAnimation(1, 0);

        animationset.addAnimation(maxAnimation);
        animationset.addAnimation(alphaAnimation);

        animationset.setDuration(durationMillis);
        animationset.setFillAfter(true);
        return animationset;
    }

}
View Code

DEMO完整下载路径:http://download.csdn.net/detail/androidsj/5525583

原文地址:https://www.cnblogs.com/androidsj/p/3119431.html