web-dev-qa-db-fra.com

L'animation de mise en page ne fonctionne pas à la première utilisation

J'ai une activité avec une liste d'éléments et lorsque vous cliquez sur un élément, je souhaite que les commandes de lecture de cet élément glissent vers le haut depuis le bas de l'écran et deviennent visibles. J'ai défini un ensemble d'animation pour la diapositive d'entrée et la diapositive et ils fonctionnent. J'ai configuré mon animationListener dans mon activité et commencé ma diapositive dans l'animation onClick d'un élément. Mon problème est que, la première fois que je lance l'application, lorsque je clique sur un élément, le rappel onClick est exécuté, mais l'animation ne se produit pas. La deuxième fois que je clique, la diapositive dans l'animation se produit, mais pas la diapositive. Troisième fois et les suivants, cela fonctionne comme prévu. Voici mes sets d'animation.

vm_slide_in.xml

    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android" 
           Android:fillAfter="true">
    <translate
        Android:fromYDelta="800"
        Android:toYDelta="0"
        Android:duration="600" />
</set>

vm_slide_out.xml

    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android" 
           Android:fillAfter="true">
    <translate
        Android:fromYDelta="0"
        Android:toYDelta="800"
        Android:duration="600" />
</set>

Voici la présentation de mon activité

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    style="@style/AppBG">
    <RelativeLayout 
        style="@style/LogoBar" 
        Android:id="@+id/logo_bar"      
        Android:layout_alignParentTop="true">
        <include layout="@layout/logobar"></include>
    </RelativeLayout>
    <RelativeLayout 
        style="@style/TitleBar" 
        Android:id="@+id/title_bar"     
        Android:layout_below="@+id/logo_bar">
        <include layout="@layout/titlebar"></include>"
        <Button style="@style/TitleBarButton"
            Android:id="@+id/vm_speaker_btn"
            Android:text="@string/vm_speaker_btn_label" 
            Android:layout_alignParentLeft="true"
            Android:layout_margin="4dp">
        </Button>
        <Button style="@style/TitleBarButton"
            Android:id="@+id/vm_edit_btn"
            Android:text="@string/vm_edit_btn_label" 
            Android:layout_alignParentRight="true"
            Android:layout_margin="4dp">
        </Button>
    </RelativeLayout>
    <ListView
        Android:id="@+id/@Android:id/list"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:layout_below="@+id/title_bar"/>
    <RelativeLayout
        Android:id="@+id/vm_control_panel"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_above="@+id/footer"
        Android:visibility="gone">
        <include layout="@layout/vm_control"/>
    </RelativeLayout>
    <RelativeLayout
        Android:id="@+id/footer"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentBottom="true">
        <include layout="@layout/taskbar"/>
    </RelativeLayout>
</RelativeLayout>

Voici la mise en page pour le contrôle inclus

    <?xml version="1.0" encoding="utf-8"?>
<merge xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <RelativeLayout 
        Android:id="@+id/vm_control"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:background="@color/dark_grey">
        <TextView
            Android:id="@+id/vm_ctl_branding"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_alignParentTop="true"
            Android:layout_centerHorizontal="true"
            Android:layout_marginTop="5dp"
            Android:text="@string/branding"
            Android:textColor="@color/white">
        </TextView>
        <TextView style="@style/TimeMark"
            Android:id="@+id/vm_timestamp"
            Android:layout_toLeftOf="@+id/vm_progress"
            Android:layout_below="@+id/vm_ctl_branding"
            Android:layout_marginRight="3dp"
            Android:text="0:00">
        </TextView>
        <SeekBar
            Android:id="@+id/vm_progress"
            Android:layout_width="200dp"
            Android:layout_height="wrap_content"
            Android:layout_below="@+id/vm_ctl_branding"
            Android:layout_centerHorizontal="true">
        </SeekBar>
        <TextView style="@style/TimeMark"
            Android:id="@+id/vm_timeleft"
            Android:layout_toRightOf="@+id/vm_progress"
            Android:layout_below="@+id/vm_ctl_branding"
            Android:layout_marginLeft="3dp"
            Android:text="-0:00">
        </TextView>
        <LinearLayout
            Android:id="@+id/vm_action_button_layout"
            Android:layout_width="fill_parent"
            Android:layout_height="wrap_content"
            Android:layout_alignLeft="@+id/vm_timestamp"
            Android:layout_alignRight="@+id/vm_timeleft"
            Android:orientation="horizontal"
            Android:layout_below="@+id/vm_progress">
            <TextView style="@style/Vm_Action_Button"
                Android:background="@drawable/vm_action_btn_call"
                Android:id="@+id/vm_callback_btn"
                Android:layout_marginRight="5dp"
                Android:text="@string/vm_action_btn_callback">
            </TextView>
            <TextView style="@style/Vm_Action_Button"
                Android:background="@drawable/vm_action_btn_delete"
                Android:id="@+id/vm_delete_btn"
                Android:layout_marginLeft="5dp"
                Android:text="@string/vm_action_btn_delete">
            </TextView>
        </LinearLayout>
    </RelativeLayout>
</merge>

De ma méthode onCreate ...

// Handle list item selections
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final Voicemail vmItem = (Voicemail) vmla.getItem(position);
        Toast.makeText(ctx, "Name: " + vmItem.getCallerName() + " Position: " + position, Toast.LENGTH_SHORT)
                .show();
        vVm_controls.startAnimation(mSlideIn);
    }
});

Et mes rappels d'animation ...

@Override
public void onAnimationStart(Animation animation) {
    vm_controls_in = !vm_controls_in;
    if (vm_controls_in) {
        vVm_controls.setVisibility(View.GONE);
    } else {
        vVm_controls.setVisibility(View.VISIBLE);
        // vVm_controls.bringToFront();
    }
}

@Override
public void onAnimationEnd(Animation animation) {
    if (!vm_controls_in) {
        try {
            Thread.sleep(1000);
            vVm_controls.startAnimation(mSlideOut);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

@Override
public void onAnimationRepeat(Animation animation) {
    // TODO Auto-generated method stub

}
39
brockoli

Comme vous l'avez découvert, le problème est la visibilité. Lorsqu'une vue est initialement définie comme disparue dans le fichier XML, Android ne restituera pas la mise en page tant que la visibilité n'est pas visible ou invisible. Si vous essayez d'animer une vue qui n'a pas encore été rendue, l'animation se produira sur la vue sans mise en page. Une fois l'animation terminée, elle sera rendue et soudainement, la vue apparaîtra sans animation. Cela fonctionne par la suite, car la vue a une mise en page, même si elle est configurée pour disparaître.

La clé est de définir la visibilité sur invisible au lieu de disparaître dans le fichier XML afin que le rendu soit encore masqué. Lorsque l'animation se produit pour la première fois, la vue apparaît et se déplace comme prévu.

110
mindriot

Bien sûr, pas 20 minutes après avoir posté cette question, j’ai compris mon problème. Comme je réglais la visibilité de ma mise en page sur "GONE", lorsque j'ai essayé de lancer l'animation dessus, cela ne s'est pas déclenché la première fois. Je ne sais pas pourquoi cela se passe à la 2ème fois et aux suivantes, mais si je règle la visibilité sur "VISIBLE" juste avant de commencer l'animation, le problème est résolu. Voici le code où je l'ai changé ...

// Handle list item selections
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final Voicemail vmItem = (Voicemail) vmla.getItem(position);
        Toast.makeText(ctx, "Name: " + vmItem.getCallerName() + " Position: " + position, Toast.LENGTH_SHORT)
                .show();
        vVm_controls.setVisibility(View.VISIBLE);
        vVm_controls.startAnimation(mSlideIn);
    }
});
11
brockoli

Je ne sais pas si c'est toujours à jour, mais oui, c'est un problème de visibilité. J'ai donc défini la visibilité dans le fichier XML sur Invisible et appelé à l'endroit où votre vue est initialisée:

view.post(new Runnable() {
    @Override
    public void run() {
        view.animate().translationY(view.getHeight());
    }
};

Maintenant l'appel

view.animate().translationY(0).setListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationStart(Animator animation) {
        super.onAnimationStart(animation);
        view.setVisibility(View.VISIBLE);
    }
}

travaille aussi sur la première fois.

5
Jason Saruulo

Avait le même problème même si je définissais la vue visible dans le début de l'animation. J'ai suivi le conseil de brockoli et l'ai mis en évidence avant de commencer l'animation et cela a fonctionné à merveille. 

AVANT:

Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.slide_left);
animation.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        view.setVisibility(View.VISIBLE);
    }

    @Override
    public void onAnimationEnd(Animation animation) { }

    @Override
    public void onAnimationRepeat(Animation animation) {       }
);
view.startAnimation(animation);

APRÈS:

Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.slide_left);
view.setVisibility(View.VISIBLE);
view.startAnimation(animation);
2
Joetron

J'ai eu le même problème dans Android 4.4.3. J'ai essayé la plupart des solutions proposées, mais une seule solution a bien fonctionné pour moi . Vous devez exécuter votre animation une fois que Windows a terminé le rendu et la meilleure méthode consiste à l'exécuter dans onWindowFocusChanged. N'utilisez pas le délai d'exécution, car cela affectera les performances de votre application dans les combinés à haute vitesse. 

@Override
public void onWindowFocusChanged (boolean hasFocus) {
   super.onWindowFocusChanged(hasFocus);
   if (hasFocus)
      yourView.startAnimation(anim);
}

plus d'informations peuvent être trouvées dans cet article: https://damianflannery.wordpress.com/2011/06/08/start-animation-in-oncreate-or-onresume-on-Android/

1
Ayman Al-Absi

J'ai eu exactement le même problème, mais en utilisant le ViewPropertyAnimator. Par exemple, vous déclarez une GridView appelée mGridView. Il ne vous reste plus qu'à appeler mGridView.animate() avec les modifications souhaitées.

L'animation de ma GridView a été déclenchée, mais en raison de circonstances inconnues, aucune animation réelle n'était visible. J'ai aussi changé tous les View.GONE en View.VISIBLE, mais cela n'a rien changé. Dans mon cas, j'ai découvert qu'il me suffisait de supprimer Android:requiresFadingEdge="vertical" dans mon XML de cette GridView particulière. Il peut ne pas être possible d'utiliser un fondu en combinaison avec ViewPropertyAnimator.

0
janwo