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.
Lassen Sie uns eine Segment Control-ähnliche Benutzeroberfläche wie diese erstellen.
Github ist hier. https://github.com/hoshi005/matched-geometry-animation
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))
}
}
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.
Durch Umschalten des Auswahlstatus hat sich auch das Erscheinungsbild geändert.
Fügen wir nun von hier aus eine Animation hinzu.
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)
})
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))
}
}
}
Die Heldenanimation ist aufregend, deshalb möchte ich verschiedene andere Dinge ausprobieren.