Ich versuche, Übergänge zwischen Fragmenten zu implementieren, die "gemeinsam genutzte Elemente" haben, wie in den neuen Materialdesignspezifikationen beschrieben. Die einzige Methode, die ich finden kann, ist die ActivityOptionsCompat.makeSceneTransitionAnimation , die meiner Meinung nach nur bei Activity funktioniert. Ich habe nach derselben Funktionalität gesucht, jedoch mit/nach Fragmenten.
Ich hatte das gleiche Problem, aber es funktionierte, indem ich ein neues Fragment aus einem anderen Fragment hinzufügte .. Der folgende Link ist sehr hilfreich, um damit anzufangen: https://developer.Android.com/training/material/animations .html # Übergänge
Nachfolgend ist mein Code, der funktioniert. Ich animiere eine ImageView
von einem Fragment zum anderen . Stellen Sie sicher, dass die View
, die Sie animieren möchten, in beiden Fragmenten den gleichen Android:transitionName
hat . Der andere Inhalt spielt keine Rolle.
Als Test könnten Sie dies in Ihre beiden XML-Layoutdateien kopieren. Stellen Sie sicher, dass das Bild vorhanden ist.
<ImageView
Android:transitionName="MyTransition"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:scaleType="centerCrop"
Android:src="@drawable/test_image" />
Dann habe ich 1 Datei in meinem res/transition
-Ordner mit dem Namen change_image_transform.xml.
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:Android="http://schemas.Android.com/apk/res/Android">
<changeImageTransform />
</transitionSet>
Jetzt können Sie loslegen. Nehmen wir an, Sie haben Fragment A mit dem Bild und möchten Fragment B hinzufügen.
Führen Sie dies in Fragment A aus:
@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;
}
}
Ich poste dies als Antwort, da ich hier neu bin und nicht kommentieren kann.
Die Übergänge des gemeinsam genutzten Elementfragments do funktionieren mit ListViews, sofern die Quell- und die Zielansicht den gleichen (und eindeutigen) Übergangsnamen haben.
Wenn Sie Ihren Listenansichtsadapter so einrichten, dass eindeutige Übergangsnamen für die gewünschten Ansichten festgelegt werden (z. B. eine Konstante + bestimmte Element-ID), ändern Sie mit und Ihr Detailfragment, um die gleichen Übergangsnamen für die Zielansichten zur Laufzeit festzulegen (onCreateView) Die Übergänge funktionieren tatsächlich!
Gemeinsam genutzte Elemente funktionieren mit Fragmenten, aber es gibt einige Dinge, die Sie beachten sollten:
Versuchen Sie nicht, die sharedElementsTransition
in der onCreateView
Ihres Fragments zu setzen. Sie müssen sie definieren, wenn Sie eine Instanz Ihres Fragments oder in onCreate
erstellen.
Beachten Sie die offizielle Dokumentation zu den möglichen Animationen für Ein-/Ausstiegsübergänge und sharedElementTransition. Sie sind nicht gleich.
Versuch und Irrtum :)
Dies sollte ein Kommentar zu der akzeptierten Antwort sein, da ich dazu nicht Stellung nehmen kann.
Die akzeptierte Antwort (von WindsurferOak und ar34z) funktioniert, mit Ausnahme eines "geringfügigen" Problems, das beim Navigieren mit dem backStack eine Nullzeigerausnahme verursacht. Es scheint, dass setSharedElementReturnTransition()
für das Zielfragment anstelle des Originalfragments aufgerufen werden sollte.
Also statt:
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
es sollte sein
fragment.setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
Der Schlüssel ist die Verwendung einer benutzerdefinierten Transaktion mit
transaction.addSharedElement(sharedElement, "sharedImage");
Shared-Element-Übergang zwischen zwei Fragmenten
In diesem Beispiel sollte eine von zwei verschiedenen ImageViews
von der ChooserFragment
in die DetailFragment
übersetzt werden.
Im ChooserFragment
-Layout benötigen wir die eindeutigen transitionName
-Attribute:
<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" />
In der ChooserFragments
-Klasse müssen wir die angeklickte View
und eine ID an die übergeordnete Activity
übergeben, die den Austausch der Fragmente übernimmt (wir benötigen die ID, um zu wissen, welche Bildressource in der DetailFragment
angezeigt wird). Wie Sie Informationen an eine übergeordnete Aktivität im Detail weitergeben, wird in einer anderen Dokumentation beschrieben.
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);
}
}
});
In der Variable DetailFragment
benötigt die Variable ImageView
des gemeinsamen Elements auch das eindeutige Attribut transitionName
.
<ImageView
Android:id="@+id/image_shared"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center"
Android:transitionName="sharedImage" />
In der onCreateView()
-Methode der DetailFragment
müssen wir entscheiden, welche Image-Ressource angezeigt werden soll (wenn dies nicht der Fall ist, wird das gemeinsam genutzte Element nach dem Übergang nicht mehr angezeigt).
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;
}
Das übergeordnete Activity
empfängt die Rückrufe und übernimmt das Ersetzen der Fragmente.
@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();
}
Nicht zu vergessen - die Transition
selbst. In diesem Beispiel wird das gemeinsam genutzte Element verschoben und skaliert.
@TargetApi(Build.VERSION_CODES.Lollipop)
public class DetailsTransition extends TransitionSet {
public DetailsTransition() {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform());
}
}
Nachfolgend finden Sie einige hilfreiche Ressourcen:
Ich habe in Fragmenten nach SharedElement gesucht und finde auf GitHub sehr nützlichen Quellcode.
1.Zunächst sollten Sie für Ihre Objekte (wie ImageView) in beiden Fragmentlayouts einen TransitionName definieren (wir fügen in Fragment A eine Schaltfläche zur Behandlung des Klickereignisses hinzu):
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);
}
}
vergiss nicht, dein "A" -Fragment in deiner Aktivität zu zeigen:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content, new SimpleFragmentA())
.commit();
}
Quelle: https://github.com/mikescamell/shared-element-transitions