[SWIFT] Animation mit MatchedGeometryEffect und @Namespace

API in Swift UI 2.0 hinzugefügt

Unter den neuen Funktionen, die in SwiftUI 2.0 hinzugefügt wurden, gab es eine API, die es einfach macht, Heldenanimationen zu erstellen, also habe ich sie für einen Moment berührt.

Formular vorerst ausgefüllt

Lassen Sie uns eine Segment Control-ähnliche Benutzeroberfläche wie diese erstellen.

Github ist hier. https://github.com/hoshi005/matched-geometry-animation

0001.gif

Entwicklungsumgebung

Mach einen Knopf

Erstellen Sie eine Ansicht der zur Auswahl verwendeten Schaltflächen. Vorher habe ich enum entsprechend definiert. Etwa 4 werden aus SF-Symbolen ausgewählt.

enum ButtonType: String, CaseIterable {
    case share = "square.and.arrow.up"
    case trash = "trash"
    case folder = "folder"
    case person = "person"
}

Die Schaltflächenansicht wird folgendermaßen erstellt. Definieren Sie für AccentColor Ihre Lieblingsfarbe in Assets entsprechend.

struct CustomButton: View {
    //Eigenschaften, die den ausgewählten Status darstellen.
    @Binding var selected: ButtonType
    //Ihr eigener Schaltflächentyp.
    let type: ButtonType
    
    var body: some View {
        ZStack {
            //Zeichnen Sie bei Auswahl einen Kreis auf den Hintergrund.
            if selected == type {
                Circle()
                    .fill(Color.accentColor) //Die Akzentfarbe sollte in Assets definiert werden.
            }
            
            Button(action: {
                selected = type //Tippen Sie auf die Schaltfläche, um die Auswahl auf sich selbst zu ändern.
            }, label: {
                //Bild von enum anzeigen.
                Image(systemName: type.rawValue)
                    .resizable()
                    .renderingMode(.original)
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 44, height: 44)
            })
        }
        .frame(width: 80, height: 80)
    }
}

Lassen Sie uns das Erscheinungsbild überprüfen, je nachdem, ob es ausgewählt ist oder nicht. Die Vorschau sieht so aus.

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            CustomButton(selected: .constant(.share), type: .share) //Ausgewählter Zustand.
            CustomButton(selected: .constant(.trash), type: .share) //Nicht ausgewählter Zustand.
        }
        .previewLayout(.fixed(width: 100, height: 100))
    }
}

スクリーンショット 2020-10-18 13.00.39.png

Ordnen Sie die Schaltflächen auf dem Bildschirm an

Ordnen wir die Schaltflächen auf dem Bildschirm an

struct ContentView: View {
    
    @State private var selected = ButtonType.share //Anfangswert des ausgewählten Zustands.
    
    var body: some View {
        HStack {
            //Drehen Sie die Aufzählung mit foreach und ordnen Sie die benutzerdefinierten Schaltflächen nebeneinander an.
            ForEach(ButtonType.allCases, id: \.self) { type in
                CustomButton(selected: $selected, type: type)
            }
        }
    }
}

Die Vorschau sieht so aus

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
            Group {
                CustomButton(selected: .constant(.share), type: .share)
                CustomButton(selected: .constant(.trash), type: .share)
            }
            .previewLayout(.fixed(width: 100, height: 100))
        }
    }
}

Lass es uns bewegen. 0002.gif Durch Umschalten des Auswahlstatus hat sich auch das Erscheinungsbild geändert. Fügen wir nun von hier aus eine Animation hinzu.

Animieren

Zunächst werden wir das Verhalten beim Tippen auf die Schaltfläche so ändern, dass die Statusänderung bei Auswahl der Schaltfläche von einer Animation begleitet wird.


//Auszug.
            
Button(action: {
    //Übergeben Sie die Verarbeitung zum Zeitpunkt des Tastendrucks bis zum Abschluss der withAnimation-Methode.
    withAnimation {
        selected = type
    }
}, label: {
    //Bild von enum anzeigen.
    Image(systemName: type.rawValue)
        .resizable()
        .renderingMode(.original)
        .aspectRatio(contentMode: .fit)
        .frame(width: 44, height: 44)
})

Stellen Sie .matchedGeometryEffect ein

Geben Sie ".matchedGeometryEffect" für die Ansicht an, die Sie animieren möchten. Es ist so, als würden Sie die zu synchronisierenden Animationen gruppieren, indem Sie ihnen eine Kennung und einen Namespace geben.

Deklarieren Sie zunächst den Namespace.

struct CustomButton: View {
    //Kürzung

    var namespace: Namespace.ID //Namespace hinzufügen.
    
    //Kürzung
}

Geben Sie dann ".matchedGeometryEffect" für die Hintergrundansicht an, die Sie animieren möchten.


//Zeichnen Sie bei Auswahl einen Kreis auf den Hintergrund.
if selected == type {
    Circle()
        .fill(Color.accentColor) //Die Akzentfarbe sollte in Assets definiert werden.
        //Der Bezeichner kann beliebig sein, solange er zwischen den Gruppen übereinstimmt, mit denen Sie die Animation synchronisieren möchten..
        .matchedGeometryEffect(id: "CustomButton", in: namespace)
}

Nehmen Sie als Nächstes Änderungen an der aufrufenden Ansichtsseite vor

struct ContentView: View {
    
    @State private var selected = ButtonType.share

    //Deklarieren Sie den Namespace mit dem @ Wamespace-Eigenschaften-Wrapper.
    @Namespace var namespace

    var body: some View {
        HStack {
            ForEach(ButtonType.allCases, id: \.self) { type in
                //Ändern Sie, um dem Argument einen Namespace zu geben.
                CustomButton(selected: $selected, type: type, namespace: namespace)
            }
        }
    }
}

Das ist es! Es ist sehr einfach zu tun!

Die Vorschau funktioniert, wenn Sie sie wie folgt ändern

struct ContentView_Previews: PreviewProvider {
    @Namespace static var namespace //Statik nicht vergessen.
    static var previews: some View {
        Group {
            ContentView()
            Group {
                CustomButton(selected: .constant(.share), type: .share, namespace: namespace)
                CustomButton(selected: .constant(.trash), type: .share, namespace: namespace)
            }
            .previewLayout(.fixed(width: 100, height: 100))
        }
    }
}

Zusammenfassung

Die Heldenanimation ist aufregend, deshalb möchte ich verschiedene andere Dinge ausprobieren.

Recommended Posts

Animation mit MatchedGeometryEffect und @Namespace
Signieren und Validieren mit java.security.Provider
Passwort-Hashing und Authentifizierung mit JBcrypt
Infrastrukturüberwachung mit Graphite und StatsD