How to apply 3d transition between two activities

2020-02-08 03:09发布

问题:

I have an android application and while switching between two activities I want to apply 3D transition... I know the method overridePendingTransition() but it does not have any animation for 3d.. So how it can be done?

回答1:

I had used 3D Cubic Transition between activities.Credit goes to Robert Heim who is developer of this program.

Below is snippet

Activity1.java

package org.vipul;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class Activity1 extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1);

        Button switchActivityBtn = (Button) findViewById(R.id.bSwitchActivity);
        switchActivityBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animatedStartActivity();
            }
        });
    }

    @Override
    protected void onResume() {
        // animateIn this activity
        ActivitySwitcher.animationIn(findViewById(R.id.container),
                getWindowManager());
        super.onResume();
    }

    private void animatedStartActivity() {
        // we only animateOut this activity here.
        // The new activity will animateIn from its onResume() - be sure to
        // implement it.
        final Intent intent = new Intent(getApplicationContext(),
                Activity2.class);
        // disable default animation for new intent
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        ActivitySwitcher.animationOut(findViewById(R.id.container),
                getWindowManager(),
                new ActivitySwitcher.AnimationFinishedListener() {
                    @Override
                    public void onAnimationFinished() {
                        startActivity(intent);
                    }
                });
    }
}

Activity2.java

package org.vipul;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class Activity2 extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity2);

        Button switchActivityBtn = (Button) findViewById(R.id.bSwitchActivity);
        switchActivityBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animatedStartActivity();
            }
        });
    }

    @Override
    protected void onResume() {
        // animateIn this activity
        ActivitySwitcher.animationIn(findViewById(R.id.container),
                getWindowManager());
        super.onResume();
    }

    private void animatedStartActivity() {
        // we only animateOut this activity here.
        // The new activity will animateIn from its onResume() - be sure to
        // implement it.
        final Intent intent = new Intent(getApplicationContext(),
                Activity1.class);
        // disable default animation for new intent
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        ActivitySwitcher.animationOut(findViewById(R.id.container),
                getWindowManager(),
                new ActivitySwitcher.AnimationFinishedListener() {
                    @Override
                    public void onAnimationFinished() {
                        startActivity(intent);
                    }
                });
    }
}

ActivitySwitcher.java

package org.vipul;

import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;

/**
 * This ActivitySwitcher uses a 3D rotation to animate an activity during its
 * start or finish.
 * 
 * see: http://blog.robert-heim.de/karriere/android-startactivity-rotate-3d-
 * animation-activityswitcher/
 * 
 * @author Robert Heim
 * 
 */
public class ActivitySwitcher {

    private final static int DURATION = 300;
    private final static float DEPTH = 400.0f;

    /* ----------------------------------------------- */

    public interface AnimationFinishedListener {
        /**
         * Called when the animation is finished.
         */
        public void onAnimationFinished();
    }

    /* ----------------------------------------------- */

    public static void animationIn(View container, WindowManager windowManager) {
        animationIn(container, windowManager, null);
    }

    public static void animationIn(View container, WindowManager windowManager,
            AnimationFinishedListener listener) {
        apply3DRotation(90, 0, false, container, windowManager, listener);
    }

    public static void animationOut(View container, WindowManager windowManager) {
        animationOut(container, windowManager, null);
    }

    public static void animationOut(View container,
            WindowManager windowManager, AnimationFinishedListener listener) {
        apply3DRotation(0, -90, true, container, windowManager, listener);
    }

    /* ----------------------------------------------- */

    private static void apply3DRotation(float fromDegree, float toDegree,
            boolean reverse, View container, WindowManager windowManager,
            final AnimationFinishedListener listener) {
        Display display = windowManager.getDefaultDisplay();
        final float centerX = display.getWidth() / 2.0f;
        final float centerY = display.getHeight() / 2.0f;

        final Rotate3dAnimation a = new Rotate3dAnimation(fromDegree, toDegree,
                centerX, centerY, DEPTH, reverse);
        a.reset();
        a.setDuration(DURATION);
        a.setFillAfter(true);
        a.setInterpolator(new AccelerateInterpolator());
        if (listener != null) {
            a.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    listener.onAnimationFinished();
                }
            });
        }
        container.clearAnimation();
        container.startAnimation(a);
    }
}

Rotate3dAnimation.java

package org.vipul;

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

/**
 * An animation that rotates the view on the Y axis between two specified
 * angles. This animation also adds a translation on the Z axis (depth) to
 * improve the effect.
 */
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);
    }
}

Activity1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#003300"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <Button
        android:id="@+id/bSwitchActivity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="switch activity" />

</LinearLayout>

Activity2.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/bSwitchActivity"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="back" />

</LinearLayout>

Manifest entries

        <activity
            android:name=".Activity1"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".Activity2"
            android:label="Activity 2" >
        </activity>


回答2:

Here is extension of @Vipul Shah code with reverse animation functionality

add following method in to "ActivitySwitcher"

 public static void animationInReverse(View container, WindowManager windowManager) {
    animationInReverse(container, windowManager, null);
}

public static void animationInReverse(View container, WindowManager windowManager, AnimationFinishedListener listener) {
    apply3DRotation(-90, 0, false, container, windowManager, listener);
}

public static void animationOutReverse(View container, WindowManager windowManager) {
    animationOut(container, windowManager, null);
}

public static void animationOutReverse(View container, WindowManager windowManager, AnimationFinishedListener listener) {
    apply3DRotation(0, 90, true, container, windowManager, listener);
}

and add this to first activity

  @Override
protected void onResume() {
    if (isFromOncreate) {
        isFromOncreate = false;
        ActivitySwitcher.animationIn(findViewById(R.id.container), getWindowManager());
    } else {
        ActivitySwitcher.animationInReverse(findViewById(R.id.container), getWindowManager());
    }
    super.onResume();
}