J'essaie d'implémenter des transitions entre des fragments qui ont des "éléments partagés" comme décrit dans les nouvelles spécifications de conception matérielle . La seule méthode que je puisse trouver est le ActivityOptionsCompat.makeSceneTransitionAnimation , qui, je crois, ne fonctionne que sur Activity. J'ai recherché cette même fonctionnalité mais avec/pour des fragments.
J'ai eu le même problème mais cela fonctionnait en ajoutant un nouveau fragment à partir d'un autre fragment . Le lien suivant est très utile pour commencer à utiliser ceci: https://developer.Android.com/training/material/animations .html # Transitions
Voici mon code qui fonctionne. J'anime une ImageView
d'un fragment à l'autre .. Assurez-vous que la View
que vous souhaitez animer a le même Android:transitionName
dans les deux fragments . L'autre contenu n'a pas d'importance.
En guise de test, vous pouvez le copier dans vos fichiers XML de mise en page. Assurez-vous que l'image existe.
<ImageView
Android:transitionName="MyTransition"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:scaleType="centerCrop"
Android:src="@drawable/test_image" />
Ensuite, j'ai 1 fichier dans mon dossier res/transition
, nommé change_image_transform.xml.
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:Android="http://schemas.Android.com/apk/res/Android">
<changeImageTransform />
</transitionSet>
Maintenant, vous pouvez commencer. Disons que vous avez le fragment A contenant l'image et que vous souhaitez ajouter le fragment B.
Exécutez ceci dans le fragment A:
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.product_detail_image_click_area:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(Android.R.transition.explode));
// Create new fragment to add (Fragment B)
Fragment fragment = new ImageFragment();
fragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
fragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(Android.R.transition.explode));
// Our shared element (in Fragment A)
mProductImage = (ImageView) mLayout.findViewById(R.id.product_detail_image);
// Add Fragment B
FragmentTransaction ft = getFragmentManager().beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack("transaction")
.addSharedElement(mProductImage, "MyTransition");
ft.commit();
}
else {
// Code to run on older devices
}
break;
}
}
Je poste ceci comme réponse, puisque je suis nouveau ici et incapable de commenter.
Les transitions de fragment d'élément partagé do fonctionnent avec ListViews, tant que les vues source et cible ont le même (et unique) nom de transition.
Si vous faites en sorte que votre adaptateur de vue de liste définisse des noms de transition uniques sur les vues souhaitées (par exemple, un identifiant d'élément constant + spécifique) et également modifie votre fragment de détail afin de définir les mêmes noms de transition sur les vues cibles au moment de l'exécution (onCreateView) les transitions fonctionnent réellement!
Les éléments partagés fonctionnent avec les fragments, mais il y a certaines choses à garder à l'esprit:
N'essayez pas de définir la sharedElementsTransition
dans la onCreateView
de votre fragment. Vous devez les définir lors de la création d'une instance de votre fragment ou dans onCreate
.
Prenez note de la documentation officielle sur les animations possibles pour les transitions entrée/sortie et sharedElementTransition. Ils ne sont pas les mêmes.
Essai et erreur :)
Cela devrait être un commentaire sur la réponse acceptée, car je suis incapable de le commenter.
La réponse acceptée (par WindsurferOak et ar34z) fonctionne, sauf pour un problème "mineur" qui a provoqué une exception de pointeur null lors de la navigation avec le backStack. Il semble que setSharedElementReturnTransition()
devrait être appelé sur le fragment cible au lieu du fragment d'origine.
Donc au lieu de:
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
cA devrait etre
fragment.setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
La clé consiste à utiliser une transaction personnalisée avec
transaction.addSharedElement(sharedElement, "sharedImage");
Transition d'éléments partagés entre deux fragments
Dans cet exemple, l’un des deux ImageViews
différents doit être traduit de ChooserFragment
en DetailFragment
.
Dans la présentation ChooserFragment
, nous avons besoin des attributs uniques transitionName
:
<ImageView
Android:id="@+id/image_first"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:src="@drawable/ic_first"
Android:transitionName="fistImage" />
<ImageView
Android:id="@+id/image_second"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:src="@drawable/ic_second"
Android:transitionName="secondImage" />
Dans la classe ChooserFragments
, nous devons passer la View
sur laquelle un utilisateur a cliqué et un ID au parent Activity
qui gère le remplacement des fragments (nous avons besoin de l'ID pour savoir quelle ressource d'image afficher dans la DetailFragment
). Comment passer des informations en détail à une activité parent est sûrement couvert dans une autre documentation.
view.findViewById(R.id.image_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 1);
}
}
});
view.findViewById(R.id.image_second).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 2);
}
}
});
Dans DetailFragment
, la ImageView
de l'élément partagé a également besoin de l'attribut unique transitionName
.
<ImageView
Android:id="@+id/image_shared"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center"
Android:transitionName="sharedImage" />
Dans la méthode onCreateView()
de la DetailFragment
, nous devons décider quelle ressource image doit être affichée (si nous ne le faisons pas, l'élément partagé disparaîtra après la transition).
public static DetailFragment newInstance(Bundle args) {
DetailFragment fragment = new DetailFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_detail, container, false);
ImageView sharedImage = (ImageView) view.findViewById(R.id.image_shared);
// Check which resource should be shown.
int type = getArguments().getInt("type");
// Show image based on the type.
switch (type) {
case 1:
sharedImage.setBackgroundResource(R.drawable.ic_first);
break;
case 2:
sharedImage.setBackgroundResource(R.drawable.ic_second);
break;
}
return view;
}
Le parent Activity
reçoit les rappels et gère le remplacement des fragments.
@Override
public void showDetailFragment(View sharedElement, int type) {
// Get the chooser fragment, which is shown in the moment.
Fragment chooserFragment = getFragmentManager().findFragmentById(R.id.fragment_container);
// Set up the DetailFragment and put the type as argument.
Bundle args = new Bundle();
args.putInt("type", type);
Fragment fragment = DetailFragment.newInstance(args);
// Set up the transaction.
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Define the shared element transition.
fragment.setSharedElementEnterTransition(new DetailsTransition());
fragment.setSharedElementReturnTransition(new DetailsTransition());
// The rest of the views are just fading in/out.
fragment.setEnterTransition(new Fade());
chooserFragment.setExitTransition(new Fade());
// Now use the image's view and the target transitionName to define the shared element.
transaction.addSharedElement(sharedElement, "sharedImage");
// Replace the fragment.
transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName());
// Enable back navigation with shared element transitions.
transaction.addToBackStack(fragment.getClass().getSimpleName());
// Finally press play.
transaction.commit();
}
Ne pas oublier - la Transition
elle-même. Cet exemple déplace et met à l'échelle l'élément partagé.
@TargetApi(Build.VERSION_CODES.Lollipop)
public class DetailsTransition extends TransitionSet {
public DetailsTransition() {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform());
}
}
J'ai cherché SharedElement par fragments et je trouve le code source très utile sur GitHub.
1. D'abord, vous devez définir nom de transition pour vos objets (comme ImageView) dans la mise en page Fragments (nous ajoutons un bouton dans le fragment A pour gérer l'événement de clic):
fragment A :
<ImageView
Android:id="@+id/fragment_a_imageView"
Android:layout_width="128dp"
Android:layout_height="96dp"
Android:layout_alignParentBottom="true"
Android:layout_centerHorizontal="true"
Android:layout_marginBottom="80dp"
Android:scaleType="centerCrop"
Android:src="@drawable/gorilla"
Android:transitionName="@string/simple_fragment_transition />
<Button
Android:id="@+id/fragment_a_btn"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentBottom="true"
Android:layout_centerHorizontal="true"
Android:layout_marginBottom="24dp"
Android:text="@string/gorilla" />
fragment B:
<ImageView
Android:id="@+id/fragment_b_image"
Android:layout_width="match_parent"
Android:layout_height="250dp"
Android:scaleType="centerCrop"
Android:src="@drawable/gorilla"
Android:transitionName="@string/simple_fragment_transition" />
change_image_transform.xml:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:Android="http://schemas.Android.com/apk/res/Android">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
</transitionSet>
fragment A:
public class FragmentA extends Fragment {
public static final String TAG = FragmentA.class.getSimpleName();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final ImageView imageView = (ImageView) view.findViewById(R.id.fragment_a_imageView);
Button button = (Button) view.findViewById(R.id.fragment_a_btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getFragmentManager()
.beginTransaction()
.addSharedElement(imageView, ViewCompat.getTransitionName(imageView))
.addToBackStack(TAG)
.replace(R.id.content, new FragmentB())
.commit();
}
});
}
}
fragment B:
public class FragmentB extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(Android.R.transition.move));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_b, container, false);
}
}
n'oubliez pas de montrer votre fragment "A" dans votre activité:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content, new SimpleFragmentA())
.commit();
}
source: https://github.com/mikescamell/shared-element-transitions