web-dev-qa-db-fra.com

Affichage de l'animation de retournement de carte sur l'ancien android

Nous le savons tous article pour savoir comment créer "card filp" animations utilisant new api. Mais comment puis-je faire cela on apis < 3.0?

Mise à jour:

Tant qu'il y a de bonnes bibliothèques faciles à utiliser comme Android-FlipView je ne pense pas que vous ayez vraiment besoin de passer par des voies aussi difficiles ...

24

J'ai trouvé la réponse. Si vous voulez faire une animation de retournement sur ALL Android VERSIONS, utilisez ceci:

Fichier de mise en page d'activité:

<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>

Comme le fichier de disposition retourne deux groupes de vues, vous pouvez mettre autre chose dans le groupe de vues et cela devrait fonctionner. Voyons maintenant les méthodes à l'intérieur de l'activité qui gère l'appel du code d'animation d'inversion:

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);
}

Et enfin la classe 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);
    }

Voici le lien pour la publication originale: Affichage de l'animation de retournement de carte sur l'ancien Android

[~ # ~] mettre à jour [~ # ~] à partir de @FMMobileFelipeMenezes.

si vous voulez que l'animation avec une échelle lisse soit inversée, changez cette partie de code en (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);

[~ # ~] mise à jour [~ # ~] de @Hesam Il y a un bon tutoriel que je recommande de le lire. Bien que ce ne soit pas aussi agréable que Android tutoriel basé sur des fragments, cela vaut la peine d'être lu et utile si vous souhaitez affecter une animation à des mises en page et des vues ainsi que l'avoir sur d'anciennes API.

tilisez l'animation à l'échelle d'Android pour simuler un retournement 3D

Projet amélioré sur github par @LenaBr

57

J'ai utilisé le code Flextra ci-dessous, et si vous voulez que l'animation avec une échelle lisse soit inversée, changez cette partie de code en (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);
7
Felipe FMMobile

J'ai joué avec ça toute la journée, et j'ai finalement atteint le but ultime - un cardflip fluide comme une animation de rotation de deux vues!

Je mets un projet de démonstration ici

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);
    }
}

et l'appelle comme ça

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);

            }
        }
    };

}

Ce sont les fragments

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);
    }
}

et enfin la vue elle-même

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>

fragment_left.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>

noter une partie du code extrait des réponses de Flextra et @FMMobileFelipeMenezes

5
Lena Bru

Il y a un bon tutoriel que je recommande de le lire. Bien que ce ne soit pas aussi agréable que Android tutoriel basé sur des fragments, cela vaut la peine d'être lu et utile si vous souhaitez affecter une animation à des mises en page et des vues ainsi que l'avoir sur d'anciennes API.

tilisez l'animation à l'échelle d'Android pour simuler un retournement 3D

2
Hesam