×

Android 3D 翻转效果的两种实现方式

96
龙衣袭
2018.10.08 23:00 字数 74

实现的效果

3Drotate.gif

第一种

在一个activity 中切换两个页面,利用API Demo中提供的工具类
API Demos 地址是

Rotate3dAnimation 工具类

public class Rotate3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation
     * @param toDegrees the end angle of the 3D rotation
     * @param centerX the X center of the 3D rotation
     * @param centerY the Y center of the 3D rotation
     * @param reverse true if the translation should be reversed, false otherwise
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees,
                             float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    @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 fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;

        final Matrix matrix = t.getMatrix();

        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();

        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

xml 文件

<FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/layout_chat_room"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:background="@color/colorAccent">

        </LinearLayout>

        <LinearLayout
            android:id="@+id/layout_circle"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:visibility="gone"
            android:background="@color/colorPrimary">

        </LinearLayout>
     
        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="切换到圈子"/>
        <Button
            android:id="@+id/btn1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="100dp"
            android:text="viewpager"/>

    </FrameLayout>

代码控制

public class Rotate3DActivity extends AppCompatActivity {

    private int mCenterX;
    private int mCenterY;
    private int depthZ = 400;
    private int duration = 600;
    private boolean isOpen = false;

    private FrameLayout mContent;
    private LinearLayout mLayoutChatRoom;
    private LinearLayout mLayoutCircle;
    private Button mBtn;
    private Button mBtn1;
    private Rotate3dAnimation mOpenFlipAnimation;
    private Rotate3dAnimation mCloseFlipAnimation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rotate3_d);
        mContent = (FrameLayout) findViewById(R.id.content);
        mLayoutChatRoom = (LinearLayout) findViewById(R.id.layout_chat_room);
        mLayoutCircle = (LinearLayout) findViewById(R.id.layout_circle);
        mBtn = (Button) findViewById(R.id.btn);
        mBtn1 = (Button) findViewById(R.id.btn1);
        mBtn1.setOnClickListener(v -> startActivity(new Intent(Rotate3DActivity.this,Rotate3DTwoActivity.class)));

        mBtn.setOnClickListener(v -> {
            //以旋转对象的中心点为旋转中心点,这里主要不要再onCreate方法中获取,因为视图初始绘制时,获取的宽高为0
            mCenterX = mContent.getWidth()/2;
            mCenterY = mContent.getHeight()/2;
            if (mOpenFlipAnimation == null) {
                initOpenAnim();
                initCloseAnim();
            }

            //用作判断当前点击事件发生时动画是否正在执行
            if (mOpenFlipAnimation.hasStarted() && !mOpenFlipAnimation.hasEnded()) {
                return;
            }
            if (mCloseFlipAnimation.hasStarted() && !mCloseFlipAnimation.hasEnded()) {
                return;
            }

            //判断动画执行
            if (isOpen) {
                mContent.startAnimation(mCloseFlipAnimation);
            }else {
                mContent.startAnimation(mOpenFlipAnimation);
            }


            isOpen = !isOpen;
            mBtn.setText(isOpen ? "关闭" : "打开");

        });
    }


    private void initOpenAnim() {
        mOpenFlipAnimation = new Rotate3dAnimation(0, 90, mCenterX, mCenterY, depthZ, true);
        mOpenFlipAnimation.setDuration(duration);
        mOpenFlipAnimation.setFillAfter(true);
        mOpenFlipAnimation.setInterpolator(new AccelerateInterpolator());
        mOpenFlipAnimation.setAnimationListener(new Animation.AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mLayoutChatRoom.setVisibility(View.GONE);
                mLayoutCircle.setVisibility(View.VISIBLE);

                //从270到360度,顺时针旋转视图,此时reverse参数为false,达到360度动画结束时视图变得可见
                Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(270, 360, mCenterX, mCenterY, depthZ, false);
                rotateAnimation.setDuration(duration);
                rotateAnimation.setFillAfter(true);
                rotateAnimation.setInterpolator(new DecelerateInterpolator());
                mContent.startAnimation(rotateAnimation);
            }
        });
    }
    /**
     * 卡牌文本介绍关闭效果:旋转角度与打开时逆行即可
     */
    private void initCloseAnim() {
        mCloseFlipAnimation = new Rotate3dAnimation(360, 270, mCenterX, mCenterY, depthZ, true);
        mCloseFlipAnimation.setDuration(duration);
        mCloseFlipAnimation.setFillAfter(true);
        mCloseFlipAnimation.setInterpolator(new AccelerateInterpolator());
        mCloseFlipAnimation.setAnimationListener(new Animation.AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mLayoutChatRoom.setVisibility(View.VISIBLE);
                mLayoutCircle.setVisibility(View.GONE);

                Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(90, 0, mCenterX, mCenterY, depthZ, false);
                rotateAnimation.setDuration(duration);
                rotateAnimation.setFillAfter(true);
                rotateAnimation.setInterpolator(new DecelerateInterpolator());
                mContent.startAnimation(rotateAnimation);
            }
        });
    }

}

第二种

ViewPager 实现 3D 翻转动画 文件

public class ThreeDPageTransformer implements ViewPager.PageTransformer {
    private final static String TAG = "FunnyPageTransformer";
    private final static float DEFAULT_MAX_ROTATION = 30.0f;

    @Override
    public void transformPage(View page, float position) {
     
        int pageWidth = page.getWidth();
        int pageHeight = page.getHeight();

        if (position < -1) { // (-Infinity, -1)
            // This page is way off-screen to the left.
            page.setRotationY(0.0f);
        } else if (position <= 0) { // [-1, 0]
            page.setPivotX(pageWidth);
            page.setPivotY(pageHeight / 2);
            page.setRotationY(DEFAULT_MAX_ROTATION * position);
        } else if (position <= 1) { // (0, 1]
            page.setPivotX(0);
            page.setPivotY(pageHeight / 2);
            page.setRotationY(DEFAULT_MAX_ROTATION * position);
        } else { // [1, +Infinity)
            // This page is way off-screen to the right.
            page.setRotationY(0.0f);
        }
    }
}

xml 文件

 <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v4.view.ViewPager>

adapter 文件

public class TabFragmentPagerAdapter extends FragmentPagerAdapter {
    private FragmentManager mfragmentManager;
    private List<Fragment> mlist;

    public TabFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
        super(fm);
        this.mlist = list;
    }

    @Override
    public Fragment getItem(int position) {
        return mlist.get(position);
    }

    @Override
    public int getCount() {
        return mlist.size();
    }
}

添加动画到 viewpager 中

public class Rotate3DTwoActivity extends AppCompatActivity {

    private static final String TAG = "Rotate3DTwoActivity";

    private ViewPager mViewPager;
    //    private ViewPagerForScrollerSpeed mViewPager;
    private List<Fragment> list;
    private TabFragmentPagerAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_rotate3_dtwo);
        if (getSupportActionBar() != null){
            getSupportActionBar().hide();
        }
        initVideoData();

        mViewPager = (ViewPager)findViewById(R.id.viewPager);
//        mViewPager = (ViewPagerForScrollerSpeed)findViewById(R.id.viewPager);
        mViewPager.setPageTransformer(true, new ThreeDPageTransformer());
        adapter = new TabFragmentPagerAdapter(getSupportFragmentManager(), list);
        mViewPager.setAdapter(adapter);
        mViewPager.setCurrentItem(0);

        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

    }
    private void initVideoData() {
        list = new ArrayList<>();

        OneFragment oneFragment = new OneFragment();

        TwoFragment twoFragment = new TwoFragment();

        ThreeFragment threeFragment = new ThreeFragment();

        list.add(oneFragment);
        list.add(twoFragment);
        list.add(threeFragment);

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

完~

开发
Web note ad 1