25

我们都知道这篇关于如何"card filp"使用new api. 但是我该怎么做on apis < 3.0呢?

更新:

只要有像android-FlipView这样好的且易于使用的库,我认为你真的不需要自己做这样的动画。

4

4 回答 4

58

找到了答案。如果你想在 上做翻转动画ALL ANDROID VERSIONS,使用这个:

活动布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_activity_root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/transparent" >
 
<RelativeLayout
android:id="@+id/main_activity_card_face"
android:layout_width="300dp"
android:layout_height="407dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="@drawable/front"
android:clickable="true"
android:onClick="onCardClick"
android:padding="5dp" >
</RelativeLayout>
 
<RelativeLayout
android:id="@+id/main_activity_card_back"
android:layout_width="300dp"
android:layout_height="407dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="@drawable/back"
android:clickable="true"
android:onClick="onCardClick"
android:visibility="gone" >
</RelativeLayout>
 
</RelativeLayout>

当布局文件翻转两个视图组时,您可以在视图组中放置任何其他内容,它应该可以工作。现在让我们看看 Activity 中处理调用翻转动画代码的方法:

public void onCardClick(View view)
{
      flipCard();
}
 
private void flipCard()
{
    View rootLayout = findViewById(R.id.main_activity_root);
    View cardFace = findViewById(R.id.main_activity_card_face);
    View cardBack = findViewById(R.id.main_activity_card_back);
 
    FlipAnimation flipAnimation = new FlipAnimation(cardFace, cardBack);
 
    if (cardFace.getVisibility() == View.GONE)
    {
        flipAnimation.reverse();
    }
    rootLayout.startAnimation(flipAnimation);
}

最后是FlipAnimation课程:

public class FlipAnimation extends Animation
{
    private Camera camera;
 
    private View fromView;
    private View toView;
 
    private float centerX;
    private float centerY;
 
    private boolean forward = true;
 
    /**
     * Creates a 3D flip animation between two views.
     *
     * @param fromView First view in the transition.
     * @param toView Second view in the transition.
     */
    public FlipAnimation(View fromView, View toView)
    {
        this.fromView = fromView;
        this.toView = toView;
 
        setDuration(700);
        setFillAfter(false);
        setInterpolator(new AccelerateDecelerateInterpolator());
    }
 
    public void reverse()
    {
        forward = false;
        View switchView = toView;
        toView = fromView;
        fromView = switchView;
    }
 
    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight)
    {
        super.initialize(width, height, parentWidth, parentHeight);
        centerX = width/2;
        centerY = height/2;
        camera = new Camera();
    }
 
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t)
    {
        // Angle around the y-axis of the rotation at the given time
        // calculated both in radians and degrees.
        final double radians = Math.PI * interpolatedTime;
        float degrees = (float) (180.0 * radians / Math.PI);
 
        // Once we reach the midpoint in the animation, we need to hide the
        // source view and show the destination view. We also need to change
        // the angle by 180 degrees so that the destination does not come in
        // flipped around
        if (interpolatedTime >= 0.5f)
        {
            degrees -= 180.f;
            fromView.setVisibility(View.GONE);
            toView.setVisibility(View.VISIBLE);
        }
 
        if (forward)
            degrees = -degrees; //determines direction of rotation when flip begins
 
        final Matrix matrix = t.getMatrix();
        camera.save();
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }

这是原始帖子的链接: Displaying card flip animation on old android

来自@FMMobileFelipeMenezes 的更新。

如果你想要平滑缩放的动画翻转,将这部分代码更改为 (applyTransformation) :

final Matrix matrix = t.getMatrix();
camera.save();
camera.translate(0, 0, Math.abs(degrees)*2);
camera.getMatrix(matrix);
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);

来自@Hesam 的更新我推荐阅读它的好教程。尽管它不如基于 Fragment 的 Android 教程那么好,但如果您想将动画分配给布局和视图以及在旧 API 上使用它,那么它值得一读并很有用。

使用 Android 的缩放动画模拟 3D 翻转

@LenaBru 改进了 github 上的项目

于 2013-04-16T18:13:29.687 回答
7

我在下面使用了 Flextra 代码,如果你想要平滑缩放的动画翻转,请将这部分代码更改为 (applyTransformation) :

    final Matrix matrix = t.getMatrix();
    camera.save();
    camera.translate(0, 0, Math.abs(degrees)*2);
    camera.getMatrix(matrix);
    camera.rotateY(degrees);
    camera.getMatrix(matrix);
    camera.restore();
    matrix.preTranslate(-centerX, -centerY);
    matrix.postTranslate(centerX, centerY);
于 2013-11-07T19:52:00.887 回答
5

我玩了一天,终于达到了终极目标——两个视图的流畅的翻牌式旋转动画!

我把演示项目放在这里

public class FlipAnimation extends Animation {
    private Camera camera;

    private View fromView;
    private View toView;

    private float centerX;
    private float centerY;

    private boolean forward = true;


    /**
     * Creates a 3D flip animation between two views.
     * 
     * @param fromView
     *            First view in the transition.
     * @param toView
     *            Second view in the transition.
     */
    public FlipAnimation(View fromView, View toView) {
        this.fromView = fromView;
        this.toView = toView;

        setDuration(1500);
        setFillAfter(false);
        // setInterpolator(new AccelerateDecelerateInterpolator());
        setInterpolator(new LinearInterpolator());
    }

    public void reverse() {

        if (forward) {
            View switchView = toView;
            toView = fromView;
            fromView = switchView;
        }
        forward = false;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        centerX = width / 2;
        centerY = height / 2;
        camera = new Camera();
    }


    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        // Angle around the y-axis of the rotation at the given time
        // calculated both in radians and degrees.
        final double radians = Math.PI * interpolatedTime;
        float degrees = (float) (180.0 * radians / Math.PI);


        //scale down the views a bit, so that they would look nice when the rotation begins

        if (interpolatedTime <= 0.05f) {
            fromView.setScaleX(1 - interpolatedTime);
            fromView.setScaleY(1 - interpolatedTime);
            toView.setScaleX(1 - interpolatedTime);
            toView.setScaleY(1 - interpolatedTime);
        }

        // Once we reach the midpoint in the animation, we need to hide the
        // source view and show the destination view. We also need to change
        // the angle by 180 degrees so that the destination does not come in
        //It is very important to call "toView.bringToFront()" and not play with the
        // visibility of the views, because if you apply this animation more than once,
        //the subsequent calls may fail
        if (interpolatedTime >= 0.5f) {
            degrees -= 180.f;
            toView.bringToFront();
          //these two lines force a layout redraw
          ((View)toView.getParent()).requestLayout();
          ((View)toView.getParent()).invalidate();


        }

        //scale the views back to their original size (Assuming original size was 1)
        if (interpolatedTime >= 0.95f) {
            fromView.setScaleX(interpolatedTime);
            fromView.setScaleY(interpolatedTime);
            toView.setScaleX(interpolatedTime);
            toView.setScaleY(interpolatedTime);
        }

        if (forward)
            degrees = -degrees; // determines direction of rotation when flip
                                // begins

        final Matrix matrix = t.getMatrix();
        camera.save();
        camera.translate(0, 0, Math.abs(degrees) * 2);
        camera.getMatrix(matrix);
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

并这样称呼它

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class MainActivity extends FragmentActivity {

private boolean showingBack;
private FragmentLeft left = new FragmentLeft();
private FragmentRight right = new FragmentRight();
private Context context;
private Handler handler;
private FlipAnimation flipAnimation;
private FlipAnimation backFlip;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    context = this;
    handler = new Handler(getMainLooper());

    getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, right, "fragmentRight").commit();
    getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, left, "fragmentLeft").commit();
    findViewById(R.id.flip).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            flipAnimation = new FlipAnimation(left.getView(), right.getView());
            backFlip = new FlipAnimation(left.getView(), right.getView());
            handler.removeCallbacks(rotate);
            handler.postDelayed(rotate, 100);
        }

    });
}

    private Runnable rotate = new Runnable() {

        @Override
        public void run() {
           //put a variable showingBack, do not rely on view properties to flip
            if (!showingBack) {
                //very important to flip both views, so that when the
                //left view goes to back and right view goes to front,
                //the right view finishes the rotation
                left.getView().startAnimation(flipAnimation);
                right.getView().startAnimation(flipAnimation);
                Toast.makeText(context, "flip", Toast.LENGTH_LONG).show();
                showingBack = true;
            } else {
                showingBack = false;
                backFlip.reverse();
                Toast.makeText(context, "backflip", Toast.LENGTH_LONG).show();
                //very important to flip both views, so that when the
                //right view goes to back and right view goes to front,
                //the left view finishes the rotation
                left.getView().startAnimation(backFlip);
                right.getView().startAnimation(backFlip);

            }
        }
    };

}

这些是碎片

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentRight extends Fragment {


    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_right, container,false);
    }
}

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentLeft extends Fragment {


    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_left, container,false);
    }
}

最后是视图本身

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="#ff151515"
    tools:context="com.example.flipviewtest.MainActivity" >

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

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true" >
    </FrameLayout>

    <Button
        android:id="@+id/flip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="flip" />

</RelativeLayout>

片段左.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#ffff0000"
     >

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ff0ffff0"
        android:layout_margin="20dp" />

</LinearLayout>

fragment_right.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff00ff00"
    android:orientation="vertical" >

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:background="#ff0000ff" />

</LinearLayout>

注意一些取自 Flextra 和 @FMMobileFelipeMenezes 答案的代码

于 2014-08-11T14:38:15.663 回答
2

我建议阅读它的好教程。尽管它不如基于 Fragment 的 Android 教程那么好,但如果您想将动画分配给布局和视图以及在旧 API 上使用它,那么它值得一读并且很有用。

使用 Android 的缩放动画模拟 3D 翻转

于 2013-10-14T16:43:52.703 回答