2017-06-12 4 views
1

Dans mon application Android, je dois implémenter une transition de scène impliquant un changement d'élévation (z-index) de l'un des éléments. Comme vous pouvez le voir sur l'image ci-dessous dans la scène de départ à gauche, l'arc bleu est affiché sous l'image du chien. Dans la transition finale affichée sur la droite, l'image du chien est affichée sous l'arc bleu. Mon désir est d'avoir une transition changeBounds de l'image commence d'abord, puis légèrement plus tard, une transition changeBounds de l'arc. Vers la moitié de la transition, le bas de l'image doit être positionné au-dessus de l'arc. A ce point, j'aimerais que l'altitude/z-index de l'image change afin que l'image du chien soit affichée sous l'arc bleu. J'ai actuellement le thème de mon application configuré pour utiliser le transitionSet suivant pour ce changement de scène.Comment puis-je animer un changement d'élévation dans le cadre d'une animation/transition de changement de scène?

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" 
    android:transitionOrdering="together" 
    android:duration="2000"> 

    <changeBounds 
     android:startDelay="0" 
     android:duration="1000" 
     android:resizeClip="false" 
     > 
     <targets> 
      <target android:targetId="@id/charlie"/> 
     </targets> 
    </changeBounds> 

    <transition class="com.motb.transitiontest.ElevationTransition"> 
     android:startDelay="0" 
     android:duration="1000" 
     <targets> 
      <target android:targetId="@id/charlie"/> 
      <target android:targetId="@id/arc1"/> 
     </targets> 
    </transition> 


    <changeBounds 
     android:startDelay="300" 
     android:duration="1000" 
     > 
     <targets> 
      <target android:targetId="@id/arc1"/> 
      <target android:targetId="@id/helloText" /> 
     </targets> 
    </changeBounds> 

</transitionSet> 

Je tente d'avoir le changement d'altitude en utilisant cette coutume « ElevationTransition » ci-dessous:

public class ElevationTransition extends Transition { 

public static final String TAG = "ElevationTransition" ; 

public ElevationTransition(Context context, AttributeSet attributes) { 
    super(context, attributes); 
} 

private static final String PROPNAME_TRANS_Z = "com.motb:transition:transz"; 
@Override 
public void captureStartValues(TransitionValues transitionValues) { 
    float translationZ = transitionValues.view.getTranslationZ() ; 
    transitionValues.values.put(PROPNAME_TRANS_Z + "_start" , translationZ); 
} 

@Override 
public void captureEndValues(TransitionValues transitionValues) { 
    float translationZ = transitionValues.view.getTranslationZ() ; 
    transitionValues.values.put(PROPNAME_TRANS_Z + "_end", translationZ); 
} 
@Override 
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, 
           TransitionValues endValues) { 
    if (startValues == null || endValues == null) { 
     return null; 
    } 
    final View view = endValues.view; 
    float startElevation = (Float) startValues.values.get(PROPNAME_TRANS_Z + "_start"); 
    float endElevation = (Float) endValues.values.get(PROPNAME_TRANS_Z + "_end"); 
    if (startElevation != endElevation) { 
     view.setTranslationZ(startElevation); 
     return ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, 
       startElevation, endElevation); 
    } 
    return null; 
} 

}

L'activité principale affiche simplement la carte vierge en utilisant la mise en page suivante:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
tools:context="com.motb.transitiontest.MainActivity" 
android:id="@+id/main" 
android:onClick="onClick" 
android:background="@drawable/treasuremap" 
> 

<FrameLayout 
    android:layout_width="match_parent" 
    android:layout_height="250dp" 
    android:id="@+id/fragmentContainer" 
    android:layout_alignParentBottom="true" 
    /> 


</RelativeLayout> 

Un clic sur la carte remplace le FrameLayout ci-dessus par un fragment dis jouer le fond « carte » qui utilise la mise en page suivante:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="250dp" 
tools:context="com.motb.transitiontest.MainActivity" 
android:id="@+id/main" 
android:background="@android:color/transparent" 
> 


<RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="160dp" 
    android:background="@drawable/arc_bg" 
    android:backgroundTint="#ff0000ff" 
    android:layout_alignParentBottom="true" 
    android:transitionName="rv1" 
    android:id="@+id/arc1" 
    android:translationZ="20dp" 

    > 

    <TextView 
     android:id="@+id/helloText" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Hello World Transition Test" 
     android:layout_marginStart="165dp" 
     android:layout_marginTop="27dp" 
     android:textSize="40dp" 
     android:gravity="left" 
     android:transitionName="tv1" 
     android:textColor="#ffffffff" 
     /> 


</RelativeLayout> 

<ImageView 
    android:layout_width="300px" 
    android:layout_height="300px" 
    android:layout_alignParentTop="true" 
    android:layout_marginTop="80dp" 
    android:layout_marginStart="20dp" 
    android:transitionName="iv1" 
    android:src="@drawable/charlie" 
    android:id="@+id/charlie" 
    android:translationZ="30dp" 
    android:stateListAnimator="@null" 
    /> 


</RelativeLayout> 

Un clic sur le fragment, commence la deuxième activité avec l'image du chien en utilisant le code XML ci-dessous:

` 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
tools:context="com.motb.transitiontest.Activity2" 
android:theme="@android:style/Theme.Translucent.NoTitleBar" 
> 


    <RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context="com.motb.transitiontest.Activity2" 
    android:layout_marginTop="200dp" 
    android:background="@drawable/arc_bg" 
    android:layout_alignParentBottom="true" 
    android:transitionName="rv1" 
    android:id="@+id/arc1" 
    android:backgroundTint="#ff0000ff" 
    android:translationZ="40dp" 
    > 


    <TextView 
     android:id="@+id/helloText" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginTop="30dp" 
     android:layout_marginLeft="50dp" 
     android:layout_marginRight="50dp" 
     android:text="Hello World Transition Test" 
     android:textSize="40dp" 
     android:textAlignment="center" 
     android:transitionName="tv1" 
     android:textColor="#ffffffff" 
     /> 


</RelativeLayout> 


<ImageView 
    android:id="@+id/charlie" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:src="@drawable/charlie" 
    android:transitionName="iv1" 
    android:scaleType="centerCrop" 
    android:translationZ="0dp" 
    android:stateListAnimator="@null" 
    /> 



</RelativeLayout>` 

Actuellement, ce que je vois, c'est que l'élévation change instantanément au début de la transition, ce qui fait que l'image du chien est obscurcie par l'arc.

+0

Une solution plus élégante et efficace sera d'écrire votre classe personnalisée pour dessiner l'image avec l'index z progressif et vous pouvez utiliser valueAnimator pour donner la douceur à votre animation – sumit

+0

@sumit S'il vous plaît fournir plus de détails sur pourquoi vous pensez un valueAnimator est meilleur qu'un ObjectAnimator dans ce cas. Qu'est-ce qui le rend plus élégant et efficace? – John

+0

Pouvez-vous également publier la hiérarchie de vue? – azizbekian

Répondre

2

J'ai vérifié le github. C'est un bug.

Je peux exécuter de manière catégorique la transition entre les scènes en utilisant Transtions et TransitionManager.go(). Mais, lorsque vous exécutez la transition entre le fragment et l'activité toujours modifie instantanément l'animation de fondu. Quelques bugs de fondu sont corrigés dans Support 26.0.0 bêta-1

  • Lorsqu'une transition de fondu est interrompue et inversée, la vue commence l'animation depuis le début. (Fix du cadre Android porté.)
  • Transition.Fade ne tient pas compte alpha initial de vue (numéro PSBA 221820)

Mais, demandez-vous, avec tous vos tripotage avez-vous jamais le vois faire un fondu réel transition? - Non. Comme ignorer tout ce qui bouge et quoi que ce soit, peux-tu l'obtenir pour faire un fondu du tout? Parce que c'est toute ma suggestion nécessaire et je ne peux pas la faire fonctionner comme vous l'avez fait fonctionner. Mais, évidemment, tout le déplacement des éléments fonctionne donc c'est un fichu bug.


Vous pouvez également faire semblant. Si vous aviez des fondus, vous pourriez simplement l'invoquer et le faire fonctionner.Vous obtenez l'animation correcte si vous changez le onCreate() dans le Activity2 être:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); 

    setContentView(R.layout.activity2); 
    findViewById(R.id.arc1).setVisibility(View.VISIBLE); 
    findViewById(R.id.arc2).setAlpha(0); 
    findViewById(R.id.arc2).animate().alpha(1).setDuration(2000).start(); 
} 

je mis que la visibilité de cette ARC1 à la bonne parce que vous aviez tort. C'est celui qui est toujours visible.

Je pense alors ajouter une animation pour la même période de temps que l'autre pour la phase, et boom. Ça marche. C'est un bug stupide. Vous ne pouvez pas obtenir des fondus entre les activités sans raison valable.


J'ai découvert l'alpha moi-même. Le premier pourrait être ce qui se passe. Ou cela pourrait être une classe de bogue complètement différente. Mais, je peux vous assurer. J'ai vérifié et fait tout correctement. Et ça a toujours échoué. Évidemment, le travail consiste à utiliser une transition de scène où ils travaillent. Peut-être ne pas utiliser une nouvelle activité en tant que telle.

Il y a un tas de solutions de contournement que vous pourriez évidemment trouver. Lancez simplement l'activité avec la mise en page qu'il est censé avoir puis configurez une scène pour passer à la mise en page appropriée. Ajoutez une autre transition à la mise en page vous-même dans la première activité. Ou quoi encore. Mais ça ne marche pas. Vous faites cette transition du fragment à l'activité et les choses bougent mais le fondu lance toujours une connotation et refuse. Il prend instantanément la visibilité de l'autre vue et sans travailler alpha non plus, il n'y a aucun moyen de rectifier cela facilement non plus.

Mon code original qui avait quelque chose de travail utilisait des scènes:

boolean to = true; 
public void onClick(View view) { 
    Scene scene; 
    ViewGroup mSceneRoot = (ViewGroup) findViewById(R.id.container); 
    if (to) { 
     Transition mFadeTransition = 
       TransitionInflater.from(this). 
         inflateTransition(R.transition.transitionset); 
     scene = Scene.getSceneForLayout(mSceneRoot, R.layout.fragment_replacement, this); 

     TransitionManager.go(scene, mFadeTransition); 
    } 
    else { 
     Transition mFadeTransition = 
       TransitionInflater.from(this). 
         inflateTransition(R.transition.backwardstransitionset); 
     scene = Scene.getSceneForLayout(mSceneRoot, R.layout.fragment_rep, this); 
     TransitionManager.go(scene, mFadeTransition); 
    } 
    to = !to; 
} 

Leaving bits de vieille réponse quand je me suis dit qu'il était de sa faute d'être incapable de mettre en œuvre mon idée claire très brillante de la façon de fais la transition. Le bug est qu'il n'a pas de fondu damné qui fonctionne, et c'était toujours le problème.


Vous ne pouvez pas animer cela simplement avec l'ordre Z. Vous changez l'ordre et ils s'appuient l'un sur l'autre plutôt que l'inverse. Pour faire ce que vous suggérez ce que vous devez faire est effectivement les deux commandes en même temps et animer leur transition avec la transparence.

Vous dessinez, Arc, Chien, un autre Arc. Ensuite, la variation de l'ordre Z est littéralement la transparence de l'arc dessiné sur le dessus. Si elle est entièrement opaque, l'Arc est sur le chien. Si c'est complètement transparent alors le chien est au-dessus de l'arc. Mais, si l'arc le plus haut est partiellement transparent, il semblera que le chien fond dans l'arc, ou l'arc fond dans le chien, selon la façon dont nous ajustons la transparence. Vous pouvez tirer le même tour ailleurs. Juste mettre la chose dans les deux endroits. Si elle est opaque, elle est couverte, mais si elle est transparente, elle ne montre que l'arc le plus bas, et un mélange de l'arc avec l'entre les objets si elle est partiellement transparente. À la fin de l'animation, placez-les dans le bon ordre. Par conséquent, pendant l'animation, vous déplacez toujours les 2 arcs à la même position. Vous devriez les voir comme le même arc. Et changez l'opacité de l'Arc en haut, et faites ce que vous faites avec ce chien.


Vidéo:

https://youtu.be/zVs3qzPU2FM


Créer des mises en page. Sandwich le bit que vous voulez changer de hauteur entre deux copies de l'autre objet. Dans l'une des mises en page, définissez la visibilité sur invisible. Donc, tous les éléments sont dans les deux dispositions dans le même ordre. Mais, dans l'un, la seconde copie de l'élément en question est invisible. Assurez-vous que les deux copies sont dans la même position dans les deux. Lorsque vous modifiez les limites d'une copie, veillez également à modifier les limites de l'autre. Déplacez-les comme une unité. Lorsque vous faites la transition entre les vues, faites disparaître l'élément tout en le déplaçant ou autre. Puisqu'il y a une deuxième copie, ça ne ressemblera pas à un fondu, ça va ressembler à un fondu.


+0

Je pense que je comprends ce que vous suggérez, mais je n'arrive toujours pas à comprendre la mise en œuvre. Votre suggestion devrait-elle fonctionner avec ActivityOptions.makeSceneTransitionAnimation? J'ai maintenant deux arcs dans la disposition de mon fragment de départ et dans la disposition de l'activité finale. J'ai ajouté un à mon transition.xml. Mais ce que je vois, c'est que le deuxième arc est immédiatement visible au lieu de s'introduire. – John

+0

Les deux arcs doivent être décalés l'un par rapport à l'autre. Vous devriez seulement les voir comme 1 arc. Et si l'arc s'estompe il devrait commencer à 0 alpha puis passer à 1. Tout en étant toujours en coïncidence avec l'autre arc au bas de la pioche. – Tatarize

+0

Je remonte toujours un animateur personnalisé, donc je ne suis pas sûr de la façon dont vous les déplacez. Et je trouve votre maquette confuse (l'image du chien a-t-elle pris le dessus pour l'image de la carte et devenir grosse ou quelque chose)? – Tatarize