J'ai fait un projet github avec juste le problème. Vous pouvez le voir/le cloner/le construire à partir d’ici: https://git.io/vMPqb
J'essaie de faire en sorte que des éléments partagés fonctionnent pour une transition de fragment.
Le projet comporte deux FAB: Feather et Plane. Plume et Avion sont des éléments partagés. Lorsque l'utilisateur clique sur Feather, la feuille de dialogue s'ouvre et Feather devrait s'animer dans la boîte de dialogue Plan. Cela ne fait pas cela pour le moment, et j'essaie de déterminer pourquoi.
Il vaut peut-être la peine de noter que j'exécute cette application sur l'API 24, de sorte que le problème ne concerne pas les transitions non prises en charge par la version 21.
Quelqu'un peut-il me dire pourquoi les transitions d'éléments partagés ne fonctionnent pas?
Pour faire écho à ce qui est dans le repo, il y a quatre fichiers importants:
Activité principale
package test.example.fabpop;
import Android.os.Bundle;
import Android.support.design.widget.FloatingActionButton;
import Android.support.transition.ChangeBounds;
import Android.support.transition.Fade;
import Android.support.v4.app.FragmentTransaction;
import Android.support.v7.app.AppCompatActivity;
import Android.view.View;
public class MainActivity extends AppCompatActivity {
FloatingActionButton fab_feather;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fab_feather = (FloatingActionButton) findViewById(R.id.initial_fab_feather);
}
public void fabClick(View view) {
SheetDialog dialogFragment = new SheetDialog();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// This seemingly has no effect. I am trying to get it to work.
transaction.addSharedElement(fab_feather, "transition_name_plane");
dialogFragment.setSharedElementEnterTransition(new ChangeBounds());
dialogFragment.setSharedElementReturnTransition(new Fade(Fade.OUT));
dialogFragment.show(transaction, "frag_tag");
}
}
activity_main.xml Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/activity_main"
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"
tools:context="test.example.fabpop.MainActivity">
<LinearLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentEnd="true"
Android:orientation="vertical">
<TextView
Android:layout_width="200dp"
Android:layout_height="wrap_content"
Android:text="Transition to a BottomSheetDialogFragment that shares this FAB"
Android:textAlignment="center"/>
<!-- Feather FAB -->
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/initial_fab_feather"
Android:layout_width="52dp"
Android:layout_height="52dp"
Android:layout_margin="16dp"
Android:layout_gravity="center"
Android:onClick="fabClick"
Android:transitionName="transition_name_feather"
Android:src="@drawable/ic_feather"
/>
</LinearLayout>
</RelativeLayout>
SheetDialog
package test.example.fabpop;
import Android.os.Bundle;
import Android.support.annotation.Nullable;
import Android.support.design.widget.BottomSheetDialogFragment;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
public class SheetDialog extends BottomSheetDialogFragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.dialog_sheet, container, false);
}
}
dialog_sheet.xml Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical" Android:layout_width="match_parent"
Android:layout_height="match_parent">
<!-- Plane FAB -->
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/final_fab_plane"
Android:layout_width="75dp"
Android:layout_height="75dp"
Android:layout_margin="16dp"
Android:transitionName="transition_name_plane"
Android:src="@drawable/ic_plane"
/>
</LinearLayout>
N'est-il pas possible d'avoir un élément partagé sur une transition entre une activité et un fragment? Peut-être n’est-ce possible que d’une activité à l’autre ou d’un fragment à l’autre, mais pas entre les deux types? Peut-être que c'est pourquoi je ne peux pas le faire fonctionner?
Mettre à jour:
J'ai maintenant essayé d'ajouter <item name="Android:windowContentTransitions">true</item>
au thème de l'application.
J'ai également essayé maintenant en m'assurant que les deux valeurs transitionName sont les mêmes sur les deux vues.
aucun de ceux-ci n'a aidé à résoudre le problème.
Commençons par souligner quelques points sur la manière dont la structure Android effectue la transition magique des éléments partagés.
Une transition d'éléments partagés n'est qu'un des mensonges du framework Android. Lorsque vous effectuez une transition d'élément partagé, vous ne partagez aucune vue entre vos activités. Par exemple, chaque activité possède une arborescence de vues indépendante.
Supposons que vous essayez de faire passer une element
identifiée par element1
de Activity1
à un element2
dans Activity2
.
Le cadre fait en sorte qu'il recherche certaines informations telles que la taille (width
, height
) et la position (x
, y
) de votre element1
dans le Activity1
. Il transmet ensuite ces informations à Activity2
, les applique sur le element2
et lance la transition d'activité en inversant l'animation de votre element2
, ce qui crée cette illusion d'élément partagé.
Cependant, ceci nécessite la création de Activity2
, la view
correspondant à element2
avant de pouvoir démarrer une animation.
Dans le cas où vous utilisez une Fragment
, appeler FragmentTransaction.commit()
servera simplement planifier votre transaction de fragment (le fragment ne sera pas créé immédiatement). Ainsi, lorsque votre Activity2
sera créé, votre element2
sera manquant (comme expliqué, son fragment contenant n'a pas encore été créé ).
Assurez-vous que votre element2
est créé avant le début de l'animation. Vous devrez donc trouver un moyen de dire au framework de ne pas faire la chose habituelle, mais d'attendre votre signal avant de créer l'animation.
Une façon de faire est de modifier votre code pour qu’il ressemble à celui-ci:
class Activity2 extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
// Tell the framework to wait.
postponeEnterTransition();
}
}
class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View element2 = getView().findViewById(R.id.element);
sharedview.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
// Tell the framework to start.
sharedview.getViewTreeObserver().removeOnPreDrawListener(this);
getActivity().startPostponedEnterTransition();
return true;
}
});
...
}
}
Mise en route avec les transitions d'activité et de fragment
Ce que vous recherchez, c’est cet exemple: https://github.com/hujiaweibujidao/FabDialogMorph . Notez que ce que vous essayez d’obtenir n’est pas une transition Android standard, vous devez créer votre propre transition de morphing, basée sur la transition ChangeBounds
. A l'origine, il a été montré dans Plaid , grâce à Nick Butcher pour ça, vous pouvez donc le vérifier pour plus de conseils et de fond.
Je viens de citer le Android Docs :
Démarrer une activité avec un élément partagé
- Attribuez un nom commun aux éléments partagés dans les deux mises en page avec l'attribut Android: transitionName.
D'après ce que je vois, vos deux fichiers XML ne partagent pas le même Android: nom de transition.
Essayez de remplacer les deux Android: transitionName dans la présentation XML (activity_main.xml & dialog_sheet.xml) par une même chaîne, par exemple: transition_plane_feather
Je n'ai pas testé les codes moi-même, mais je pense que cela pourrait être un bon point de départ.
Si vous envisagez de mettre pleinement en œuvre Material Design sans compatibilité avec les niveaux d'API inférieurs (pré-Lollipop), je vous recommande vivement de consulter un exemple créé par un concepteur Google UI/UX: https://github.com/nickbutcher/ plaid
Découvrez également l'excellente vidéo YouTube complémentaire à cet exemple: https://www.youtube.com/watch?v=EjTJIDKT72M
Il vous montre quelques-unes des meilleures astuces et pratiques que vous pouvez utiliser pour implémenter entièrement la conception de matériaux ainsi que les transitions d'éléments partagés.