webentwicklung-frage-antwort-db.com.de

Wie starte ich einen gemeinsamen Elementübergang mit Fragmenten?

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.

54
unchosen

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;
    }
}
42
ar34z

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!

21

Gemeinsam genutzte Elemente funktionieren mit Fragmenten, aber es gibt einige Dinge, die Sie beachten sollten:

  1. 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.

  2. Beachten Sie die offizielle Dokumentation zu den möglichen Animationen für Ein-/Ausstiegsübergänge und sharedElementTransition. Sie sind nicht gleich.

  3. Versuch und Irrtum :)

11
Jordy

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));

https://github.com/tevjef/Rutgers-Course-Tracker/issues/8

3
Paul L

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());
    }

}
0
Marius
0
Lym Zoy

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" />
  1. Dann sollten Sie diesen Code in Ihre Übergangsdatei im Übergangsverzeichnis schreiben (wenn Sie dieses Verzeichnis nicht haben, erstellen Sie eines: res> new> Android Ressourcenverzeichnis> Ressourcentyp = Übergang> name = change_image_transform):

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>
  1. Im letzten Schritt sollten Sie Codes in Java vervollständigen:

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

0
yasin