webentwicklung-frage-antwort-db.com.de

Shared Element Transition funktioniert nicht

Ich habe ein Github-Projekt nur mit dem Thema gemacht. Sie können es von hier aus sehen/klonen/erstellen: https://git.io/vMPqb


Ich versuche, gemeinsame Elemente für einen Fragment-Übergang zu erhalten.

Es gibt zwei FABs im Projekt - Feder und Flugzeug. Feder und Flugzeug sind gemeinsame Elemente. Wenn Sie auf Feder klicken, wird der SheetDialog geöffnet, und Feder sollte sich im Ebenendialogfeld befinden. Im Moment tut es das nicht, und ich versuche zu ermitteln, warum.

Es kann sich lohnen, darauf hinzuweisen, dass ich dies auf API 24 ausführte, sodass Probleme mit Übergängen, die nicht unter Version 21 unterstützt werden, nicht das Problem sind.

Kann mir jemand sagen, warum gemeinsame Elementübergänge nicht funktionieren?

Um zu bestätigen, was im Repo enthalten ist, gibt es vier wichtige Dateien:

Hauptaktivität

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>

Ist es nicht möglich, ein gemeinsames Element an einem Übergang zwischen einer Aktivität und einem Fragment zu haben? Vielleicht ist nur zwischen Aktivität zu Aktivität oder Fragment zu Fragment möglich, jedoch nicht zwischen den beiden Typen? Vielleicht kann ich es deshalb nicht zum Laufen bringen?

Aktualisieren:

Ich habe jetzt versucht, <item name="Android:windowContentTransitions">true</item> zum Design der App hinzuzufügen. 

Ich habe jetzt auch versucht, sicherzustellen, dass beide TransitionName-Werte in beiden Ansichten gleich sind.

keines von ihnen hat dazu beigetragen, das Problem zu beheben.

17
atwrk

Bevor wir eintauchen ...

Lassen Sie uns zunächst einige Punkte hervorheben, wie das Android-Framework den Übergang zu magischen freigegebenen Elementen durchführt.

Ein Übergang zu einem gemeinsamen Element ist nur eine Lüge des Android-Frameworks. Wenn Sie einen Übergang für ein gemeinsames Element durchführen, geben Sie eigentlich keine Ansicht für Ihre Aktivitäten frei, z. B. hat jede Aktivität eine unabhängige Ansichtsbaumstruktur.

Angenommen, Sie versuchen, eine durch element1 identifizierte element von Activity1 auf einen element2 in Activity2 zu übertragen. 

Was das Framework tut, ist, dass es nach bestimmten Informationen sucht, wie z. B. der Größe (width, height) und der Position (x, y) Ihres element1 im Activity1. Anschließend übergibt er diese Informationen an Activity2, wendet sie auf element2 an und startet den Aktivitätsübergang durch die umgekehrte Animation Ihres element2, wodurch diese Illusion des gemeinsam genutzten Elements entsteht.

Dies setzt jedoch voraus, dass der Activity2 erstellt wird und die view, die element2 entspricht, gefunden werden muss, bevor eine Animation gestartet werden kann.

Wenn Sie eine Fragment verwenden, wird der Aufruf von FragmentTransaction.commit() einfach Ihre Fragmenttransaktion einplanen (das Fragment wird nicht sofort erstellt). Wenn Ihr Activity2 erstellt wird, fehlt Ihr element2 (wie bereits erwähnt, weil das Fragment noch nicht erstellt wurde ).

Lösung

Stellen Sie sicher, dass Ihr element2 erstellt wurde, bevor die Animation startet. Sie müssen also einen Weg finden, dem Framework mitzuteilen, dass es nicht das Übliche tun soll, sondern warten Sie auf Ihr Signal, bevor Sie die Animation erstellen.

Eine Möglichkeit, dies zu tun, besteht darin, Ihren Code so zu ändern, dass er dem folgenden ähnelt:

Aktivität2

class Activity2 extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        // Tell the framework to wait.
        postponeEnterTransition();
    }
}

Fragment2

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

Lesen Sie weiter

Erste Schritte mit Aktivitäts- und Fragmentübergängen

8
Anix PasBesoin

Was Sie suchen, ist dieses Beispiel: https://github.com/hujiaweibujidao/FabDialogMorph . Beachten Sie, dass das, was Sie zu erreichen versuchen, kein Standard-Übergang von Android ist eigener Morphing-Übergang, basierend auf ChangeBounds-Übergang. Ursprünglich wurde es in Plaid gezeigt, dank Nick Butcher dafür, sodass Sie weitere Tipps und Hintergründe finden können.

1
rom4ek

Zitieren Sie einfach die Android-Dokumente

Aktivität mit einem gemeinsamen Element starten

  1. Weisen Sie den gemeinsam genutzten Elementen in beiden Layouts einen allgemeinen Namen mit dem Attribut Android: transitionName zu.

Soweit ich sehe, teilen beide XMLs nicht dasselbe Android: transitionName.

Ändern Sie beide Android: transitionName im XML-Layout (activity_main.xml und dialog_sheet.xml) in dieselbe Zeichenfolge. Beispiel: transition_plane_feather

Ich habe die Codes nicht selbst getestet, aber ich denke, das könnte ein guter Ausgangspunkt sein.

Bonus-Tipp

Wenn Sie vorhaben, Material Design ohne Kompatibilität mit niedrigeren API-Levels (vor Lollipop) vollständig zu implementieren, empfehle ich Ihnen dringend, ein Beispiel eines Google UI/UX Designers anzusehen: https://github.com/nickbutcher/ kariert

Schauen Sie sich auch das hervorragende YouTube-Video zu diesem Beispiel an: https://www.youtube.com/watch?v=EjTJIDKT72M

Es zeigt Ihnen einige der besten Tricks und Praktiken, die Sie zur vollständigen Implementierung des Materialdesigns sowie für gemeinsame Elementübergänge verwenden können.

1
Nicholas Lie