web-dev-qa-db-fra.com

Création d'une animation 3D 3D sous Android avec XML

J'ai créé une bascule 3D d'une vue à l'aide de de ce tutoriel Android Cependant, je l'ai fait par programme et j'aimerais tout faire en XML, si possible. Je ne parle pas simplement de réduire une vue vers le milieu, puis de revenir en arrière, mais d'un retournement 3D réel. 

Est-ce possible via XML?

23

Voici la réponse, même si cela ne fonctionne qu'avec les versions 3.0 et supérieures. 

1) Créez un nouveau dossier de ressources appelé "animateur".

2) Créez un nouveau fichier .xml que j'appellerai "retournement". Utilisez le code XML suivant:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:valueFrom="0" Android:valueTo="360" Android:propertyName="rotationY" >
</objectAnimator>

Non, les balises objectAnimator ne commencent pas par un "O" majuscule.

3) Lancez l'animation avec le code suivant:

ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(mContext, R.animator.flipping); 
anim.setTarget(A View Object reference goes here i.e. ImageView);
anim.setDuration(3000);
anim.start();

J'ai tout ça de ici .

55

Étant donné que les réponses à cette question sont relativement anciennes, voici une solution plus moderne reposant sur ValueAnimators ..__ Cette solution implémente un véritable basculement 3D visuellement attrayant, car retourner (c'est comme ça que Apple le fait).

Nous avons d’abord créé le ValueAnimator:

mFlipAnimator = ValueAnimator.ofFloat(0f, 1f);
mFlipAnimator.addUpdateListener(new FlipListener(frontView, backView));

Et le listener de mise à jour correspondant:

public class FlipListener implements ValueAnimator.AnimatorUpdateListener {

    private final View mFrontView;
    private final View mBackView;
    private boolean mFlipped;

    public FlipListener(final View front, final View back) {
        this.mFrontView = front;
        this.mBackView = back;
        this.mBackView.setVisibility(View.GONE);
    }

    @Override
    public void onAnimationUpdate(final ValueAnimator animation) {
        final float value = animation.getAnimatedFraction();
        final float scaleValue = 0.625f + (1.5f * (value - 0.5f) * (value - 0.5f));

        if(value <= 0.5f){
            this.mFrontView.setRotationY(180 * value);
            this.mFrontView.setScaleX(scaleValue);
            this.mFrontView.setScaleY(scaleValue);
            if(mFlipped){
                setStateFlipped(false);
            }
        } else {
            this.mBackView.setRotationY(-180 * (1f- value));
            this.mBackView.setScaleX(scaleValue);
            this.mBackView.setScaleY(scaleValue);
            if(!mFlipped){
                setStateFlipped(true);
            }
        }
    }

    private void setStateFlipped(boolean flipped) {
        mFlipped = flipped;
        this.mFrontView.setVisibility(flipped ? View.GONE : View.VISIBLE);
        this.mBackView.setVisibility(flipped ? View.VISIBLE : View.GONE);
    }
}

C'est tout!

Après cette configuration, vous pouvez retourner les vues en appelant

mFlipAnimator.start();

et inverser le flip en appelant

mFlipAnimator.reverse();

Si vous voulez vérifier si la vue est retournée, implémentez et appelez cette fonction:

private boolean isFlipped() {
    return mFlipAnimator.getAnimatedFraction() == 1;
}

Vous pouvez également vérifier si la vue est en train de basculer en implémentant cette méthode:

private boolean isFlipping() {
    final float currentValue = mFlipAnimator.getAnimatedFraction();
    return (currentValue < 1 && currentValue > 0);
}

Vous pouvez combiner les fonctions ci-dessus pour implémenter une fonction Nice pour basculer le retournement, selon que le retournement est activé ou non:

private void toggleFlip() {
    if(isFlipped()){
        mFlipAnimator.reverse();
    } else {
        mFlipAnimator.start();
    }
}

C'est tout! Simple et facile. Prendre plaisir!

22
A. Steenbergen

J'ai créé un programme simple pour créer une bascule de vue comme:

enter image description here

Dans Activity, vous devez créer cette méthode pour ajouter flip_rotation dans la vue.

private void applyRotation(View view) 
{
    final Flip3dAnimation rotation = new Flip3dAnimation(view);
    rotation.applyPropertiesInRotation();
    view.startAnimation(rotation);
}

pour cela, vous devez copier la classe principale utilisée pour fournir flip_rotation.

import Android.graphics.Camera;
import Android.graphics.Matrix;
import Android.util.Log;
import Android.view.View;
import Android.view.animation.AccelerateInterpolator;
import Android.view.animation.Animation;
import Android.view.animation.Transformation;

public class Flip3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private Camera mCamera;

    public Flip3dAnimation(View view) {
        mFromDegrees = 0;
        mToDegrees = 720;
        mCenterX = view.getWidth() / 2.0f;
        mCenterY = view.getHeight() / 2.0f;
    }

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

    public void applyPropertiesInRotation()
    {
        this.setDuration(2000);
        this.setFillAfter(true);
        this.setInterpolator(new AccelerateInterpolator());
    }

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

        Log.e("Degree",""+degrees) ;
        Log.e("centerX",""+centerX) ;
        Log.e("centerY",""+centerY) ;

        camera.rotateY(degrees);

        camera.getMatrix(matrix);
        camera.restore();

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

    }

}
7
Tushar Pandey

Une des meilleures solutions pour retourner l’image sans utiliser l’animation de ressource est la suivante: -

  ObjectAnimator animation = ObjectAnimator.ofFloat(YOUR_IMAGEVIEW, "rotationY", 0.0f, 360f);  // HERE 360 IS THE ANGLE OF ROTATE, YOU CAN USE 90, 180 IN PLACE OF IT,  ACCORDING TO YOURS REQUIREMENT 

  animation.setDuration(500); // HERE 500 IS THE DURATION OF THE ANIMATION, YOU CAN INCREASE OR DECREASE ACCORDING TO YOURS REQUIREMENT
  animation.setInterpolator(new AccelerateDecelerateInterpolator());
  animation.start();
4

Le tutoriel ou le lien de om252345 ne produit pas de retournements 3D crédibles. Une simple rotation sur l'axe des ordonnées n'est pas ce qui se fait sous iOS. L'effet de zoom est également nécessaire pour créer cette agréable sensation de retournement. Pour cela, jetez un coup d’œil à cet exemple . Il existe également une vidéo ici .

4
Ephraim
  1. La méthode la plus simple consiste à utiliser ViewPropertyAnimator

    mImageView.animate().rotationY(360f);
    

    En utilisant l'interface fluide, vous pouvez créer une animation plus complexe et plus excitante . vous pouvez activer l'accélération matérielle en appelant simplement la méthode withLayer () (API 16). Plus ici

  2. Si vous voulez savoir comment créer une animation de film 3D, suivez ici et ici .

  3. J'ai implémenté ma propre solution uniquement pour une recherche. Elle inclut: annulation, accélération, support API> = 15 et est basée sur Property Animation . L’animation complète comprend 4 parties, 2 pour chaque côté. Chaque objectAnimator a un écouteur qui définit l'index d'animation en cours et représente une image dans la valeur onAnimationStart et la durée de lecture actuelle dans le onAnimationCancel .

    mQuarterAnim1.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            mQuarterCurrentAnimStartIndex = QUARTER_ANIM_INDEX_1;
            mImageView.setImageResource(mResIdFrontCard);
        }
    
        @Override
        public void onAnimationCancel(Animator animation) {
            mQuarterCurrentAnimPlayTime = ((ObjectAnimator) animation).getCurrentPlayTime();
        }
    });
    

    Pour commencer définir un appel

    mAnimatorSet.play(mQuarterAnim1).before(mQuarterAnim2)
    

    Si AnimatorSet a été annulé, nous pouvons calculer le delta et exécuter l'animation inversée en fonction de l'animation d'index actuelle et de la valeur de la durée de lecture actuelle.

    long degreeDelta = mQuarterCurrentAnimPlayTime * QUARTER_ROTATE / QUARTER_ANIM_DURATION;
    
    if (mQuarterCurrentAnimStartIndex == QUARTER_ANIM_INDEX_1) {
        mQuarterAnim4.setFloatValues(degreeDelta, QUARTER_FROM_1);
        mQuarterAnim4.setDuration(mQuarterCurrentAnimPlayTime);
    
        mAnimatorSet.play(mQuarterAnim4);
    }
    

    exemple complet ici

3
yoAlex5

Ajoutant à la bonne réponse de A. Steenbergen. Lors du retournement de la même vue (mise à jour d'une TextView par exemple), j'ai supprimé le changement View.Visibility dans le constructeur afin de maintenir la transition plus douce.

public FlipListener(final View front, final View back) {
    this.mFrontView = front;
    this.mBackView = back;
}
0
seekingStillness