web-dev-qa-db-fra.com

Android: utiliser ObjectAnimator pour traduire une vue avec des valeurs fractionnaires de la dimension de la vue

Il semble que les anciennes animations de vue (translate, scale, etc.) ne sont plus acceptées par le AnimationInflater, au moins comme pour ICS. J'ai lu son code dans 4.0.4, et il n'attend explicitement que les éléments XML set, objectAnimator, animator.

Même si la documentation sur http://developer.Android.com/guide/topics/resources/animation-resource.html continue d'inclure les animations de vue, elles semblent obsolètes. Essayer de les utiliser entraîne, par exemple, l'erreur Java.lang.RuntimeException: Unknown animator name: translate.

En tant que tel, il devient nécessaire d'utiliser le ObjectAnimator d'Android. Cependant, il n'accepte pas les valeurs fractionnaires de la dimension associée de lui-même ou de son parent (largeur pour translationX, par exemple) comme les anciennes animations de vue le faisaient sous la forme "75%p".

Construire le ObjectAnimator manuellement au moment de l'exécution, en récupérant par programme la taille du fragment, n'est pas possible car le FragmentTransaction n'accepte que les animations déclaratives spécifiées par un résid.

Mon objectif est de traduire hors écran un fragment qui remplit une activité entière (je fais essentiellement une transition entre deux fragments). Il s'agit de l'implémentation existante de TranslationAnimation (slide_in_right.xml, qui avec son homologue slide_out_left.xml n'est pas exposé pour une raison quelconque dans Android.R.anim, et je dois donc les dupliquer dans ma base de code):

<set xmlns:Android="http://schemas.Android.com/apk/res/Android">
<translate
    Android:fromXDelta="100%p"
    Android:toXDelta="0"
    Android:duration="@Android:integer/config_mediumAnimTime"/>
</set>

Mon niveau d'API est défini sur 14.

Merci!

40
orospakr

En fait, les animateurs d'objets acceptent des valeurs fractionnaires. Mais peut-être n'avez-vous pas compris le concept sous-jacent d'un objectAnimator ou plus généralement d'un animateur de valeur. Un animateur de valeurs animera une valeur liée à une propriété (telle qu'une couleur, une position à l'écran (X, Y), un paramètre alpha ou tout ce que vous voulez). Pour créer une telle propriété (dans votre cas xFraction et yFraction), vous devez créer vos propres getters et setters associés à ce nom de propriété. Disons que vous souhaitez traduire un FrameLayout de 0% à 25% de la taille de votre écran entier. Ensuite, vous devez créer une vue personnalisée qui encapsule les objets FrameLayout et écrire vos getters et setters.

public class SlidingFrameLayout extends FrameLayout
{
    private static final String TAG = SlidingFrameLayout.class.getName();

    public SlidingFrameLayout(Context context) {
        super(context);
    }

    public SlidingFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public float getXFraction()
    {
        int width = getWindowManager().getDefaultDisplay().getWidth();
        return (width == 0) ? 0 : getX() / (float) width;
    }

    public void setXFraction(float xFraction) {
        int width = getWindowManager().getDefaultDisplay().getWidth();
        setX((width > 0) ? (xFraction * width) : 0);
    }
}

Ensuite, vous pouvez utiliser la méthode xml pour déclarer l'animateur d'objet en plaçant xFraction sous l'attribut xml de propriété et le gonfler avec un AnimatorInflater

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator 
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:propertyName="xFraction" 
Android:valueType="floatType"
Android:valueFrom="0"
Android:valueTo="0.25" 
Android:duration="500"/>

ou vous pouvez simplement utiliser le code de ligne Java

ObjectAnimator oa = ObjectAnimator.ofFloat(menuFragmentContainer, "xFraction", 0, 0.25f);

J'espère que cela vous aide!

Olivier,

51
Olivier Marty

L'implémentation du SDK Android de FragmentTransaction attend un Animator tandis que, pour une raison obscure, l'implémentation de la bibliothèque de support attend un Animation, si vous utilisez l'implémentation de fragment de la bibliothèque de support, votre animation de traduction sera travail

9
sherpya

Voici un important gotcha pour ceux qui essaient de créer des animations de vue comme translate et scale.

Les animations des propriétés sont situées dans un répertoire nommé "animateur": res/animator/filename.xml

MAIS, les animations de vue doivent être placées dans un répertoire simplement appelé "anim": res/anim/filename.xml

J'ai d'abord mis mon animation de vue dans un dossier "animateur", et j'étais confus à propos de Android Studio se plaignant du fait que la traduction n'était pas un élément valide. Donc, NO , les animations de vue ne sont pas obsolètes. Elles ont juste leur propre emplacement pour une raison déroutante.

8
Johannes

voici un exemple de travail complet (œuvres décrites par l'auteur de la réponse acceptée.)

Appuyez sur le bouton pour basculer entre 2 fragments A et B (par animation de diapositives de droite à gauche). Les fragments sont juste du texte stupide (AAAAAA et BBBBB) avec des arrière-plans différents.

MainActivity.Java

package com.example.slidetrans;

import Android.app.Activity;
import Android.app.Fragment;
import Android.app.FragmentManager;
import Android.app.FragmentTransaction;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.View;
import Android.view.View.OnClickListener;
import Android.widget.Button;


public class MainActivity extends Activity {

    private static final String TAG = "Main";

    boolean showingA = true;
    Button button;

    A a;
    B b;

    private void incarnate(FragmentManager fm){
        int layoutId = R.id.frame;
        boolean fragmentWasNull = false;
        Fragment f = fm.findFragmentById(layoutId);
        if (f == null){
            Log.i(TAG, "fragment is null");
            if (showingA){
                f = a = new A();
            } else {
                f = b = new B();
            }
            fragmentWasNull = true;
        } else {
            Log.i(TAG, "fragment is not null");
            showingA = (f instanceof A);
            updateButtonText();
        }
        if (fragmentWasNull){
            FragmentTransaction ft = fm.beginTransaction();
            ft.add(layoutId, showingA ? a : b,  "main").commit(); 
        }
    }
    private void updateButtonText(){
        button.setText(showingA ? "slide in B" : "slide in A");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        FragmentManager fm = getFragmentManager();
        button = (Button)findViewById(R.id.button);
        incarnate(fm);
        OnClickListener listener = new OnClickListener() {
            @Override
            public void onClick(View v) {
                FragmentManager fm = getFragmentManager();
                FragmentTransaction transaction = fm.beginTransaction();
                transaction.setCustomAnimations(R.anim.in, R.anim.out);
                transaction.replace(R.id.frame, showingA ? new B() : new A()).commit();
                showingA = !showingA;
                updateButtonText();
            }
        };
        button.setOnClickListener(listener);
    }
}

LL.Java

package com.example.slidetrans;

import Android.content.Context;
import Android.util.AttributeSet;
import Android.widget.LinearLayout;

public class LL extends LinearLayout {

    public LL(Context context) {
        super(context);
    }

    public LL(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public float getXFraction() {
        final int width = getWidth();
        if (width != 0) return getX() / getWidth();
        else return getX();
    }

    public void setXFraction(float xFraction) {
        final int width = getWidth();
        float newWidth = (width > 0) ? (xFraction * width) : -9999;
        setX(newWidth);
    }
}

main.xml (mise en page)

<?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"
>
    <Button
        Android:id="@+id/button"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="slide in B" />

    <FrameLayout
        Android:id="@+id/frame"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent" >

    </FrameLayout>

</LinearLayout>

a.xml (mise en page)

<?xml version="1.0" encoding="utf-8"?>
<com.example.slidetrans.LL xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical"
    Android:background="#00FF00"
>

    <TextView
        Android:id="@+id/aText"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="AAAAAAAAAAAAAAAAAA"
        Android:textSize="30sp"
        Android:textStyle="bold"
    />

</com.example.slidetrans.LL>

b.xml (mise en page)

<?xml version="1.0" encoding="utf-8"?>
<com.example.slidetrans.LL xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical"
    Android:background="#FFFF00"
>

    <TextView
        Android:id="@+id/bText"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:textSize="30sp"
        Android:textStyle="bold"
        Android:text="BBBBBBBBBB"
    />

</com.example.slidetrans.LL>

in.xml (anim)

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <objectAnimator
    Android:duration="500"
    Android:interpolator="@Android:anim/linear_interpolator"
    Android:propertyName="xFraction"
    Android:valueFrom="1.0"
    Android:valueTo="0.0"
    Android:valueType="floatType" />

</set>

out.xml (anim)

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <objectAnimator
    Android:duration="500"
    Android:interpolator="@Android:anim/linear_interpolator"
    Android:propertyName="xFraction"
    Android:valueFrom="0.0"
    Android:valueTo="-1.0"
    Android:valueType="floatType" />

</set>
4
mathheadinclouds

Les animations de vue ne sont pas obsolètes. Si vous utilisez Eclipse, vous pouvez les trouver sous une animation d'interpolation comme type de ressource lors de la création d'un nouveau fichier XML Android Android.

0
Ahmad Al-Ibrahim