[SWIFT] iOS App Entwicklung: Timer App (10. Animation erstellen)

スクリーンショット 2020-10-28 11.35.01.png

Artikel

Die Punkte zum Erstellen einer Timer-App werden in mehreren Artikeln veröffentlicht. In diesem Artikel werde ich Ihnen zeigen, wie Sie eine Animation erstellen, um den Countdown-Timer optisch ansprechend zu gestalten.

Umgebung

Git-Repository

Sie können den Beispielcode unter der folgenden Git-Repository-URL sehen. https://github.com/msnsk/Qiita_Timer.git

Verfahren

  1. Überlegen Sie, welche Art von Animation Sie möchten
  2. Erstellen Sie eine animierte Ansicht
  3. Bereiten Sie eine Figur zum Animieren vor
  4. Geben Sie die Farbe der Figur an und ändern Sie sie ständig
  5. Wenden Sie eine Animation an, die die Form verschiebt
  6. Platzieren Sie die animierte Ansicht in der Hauptansicht

1. Überlegen Sie, welche Art von Animation Sie möchten

Beim Betrachten der Hauptansicht im Moment gibt es eine kleine Lücke zwischen der TimerView / PickerView und der ProgressBarView. Daher möchte ich die Form in diesem leeren Raum animieren, damit sie visuell Spaß macht.

Bereiten Sie als konkrete Bewegung zwei kleine Kreise vor, platzieren Sie sie an einer Position, die um 12 Uhr die Innenseite des Fortschrittsbalkens berührt, und nehmen Sie sich einige Sekunden Zeit, um den Fortschrittsbalken zu durchlaufen. Ich werde es schaffen. Die beiden Kreise bewegen sich im Uhrzeigersinn bzw. gegen den Uhrzeigersinn. Und nach einer Runde überlappt es sich genau um 12 Uhr wieder.

Stellen Sie außerdem die Transparenz der beiden Kreise auf 0,5 ein, damit sich die Farben mischen und die Transparenz 1 wird, wenn sie sich überlappen. Die Farben der beiden Kreise ändern sich wie der Fortschrittsbalken ständig.

2. Erstellen Sie eine animierte Ansicht

Erstellen Sie eine neue Datei mit dem Namen AnimationView. Bereiten Sie eine Instanz der TimeManager-Klasse in den Eigenschaften der Animationsstruktur vor. Stellen Sie dem Eigenschafts-Wrapper @EnvironmentObject das Präfix voran, da er immer auf den Wert dieser Eigenschaft verweist.

Wenn Sie eine Figur in einer Animation anordnen, wird die Position basierend auf der Bildschirmgröße festgelegt. Bereiten Sie daher die Eigenschaft für die Bildschirmgröße im Voraus vor (hier wird nur die Breite verwendet, das Gerät wird jedoch zur Seite gedreht. Wenn Sie das Layout anpassen möchten, benötigen Sie auch die Höhe.

AnimationView.swift


import SwiftUI

struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager
    
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    
    var body: some View {

    }
}

3. Bereiten Sie eine Figur zum Animieren vor

Die Animation, die wir erstellen möchten, bewegt zwei Kreise.

Fügen Sie zwei Circle () -Komponenten in den Körper ein {}. Überlagern Sie diese mit ZStack {}. Es ist egal, welches oben ist.

Geben Sie im Modifikator .frame () eine Größe von 20 an. Es ist ein ziemlich kleiner Kreis.

Der Modifikator .offset () verschiebt die Platzierungsposition vertikal nach oben. Verschieben Sie es nun vertikal (y) nach oben, basierend auf der Eigenschaft screenWidth, in der die Breite des zuvor vorbereiteten Bildschirms gespeichert ist. Wenn Sie es nach oben verschieben, ist es ein negativer Wert. Im Gegenteil, wenn Sie es nach unten verschieben möchten, ist es ein positiver Wert. Die Länge der Verschiebung ist die Bildschirmbreite x 0,38. Dadurch wird ein Kreis über der Bildschirmmitte ungefähr innerhalb des Fortschrittsbalkens platziert.

AnimationView.swift


struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager
    
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    
    var body: some View {
        ZStack{
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
            
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
        }
    }
}

4. Geben Sie die Farbe der Figur an und ändern Sie sie ständig

Bereiten Sie als Nächstes eine Eigenschaft vor, die den Farbton der beiden Kreise angibt. Die Anfangswerte sind 0,5 bzw. 0,3.

    @State var costomHueA: Double = 0.5
    @State var costomHueB: Double = 0.3

Verwenden Sie im Modifikator .foregroundColor die Werte der obigen Farbtöneigenschaften, um den Kreis durch Angeben von Farbton, Sättigung, Helligkeit und Deckkraft einzufärben. Fügen Sie zunächst die obigen Eigenschaften in das Argument hue ein. Und da die Deckkraft beide Kreise 0,5 und durchscheinend macht, geben wir einen Maximalwert von 1 für Sättigung und Helligkeit an.

//Für den ersten Kreis
.foregroundColor(Color(hue: self.costomHueA, saturation: 1.0, brightness: 1.0, opacity: 0.5))
//Für den zweiten Kreis
.foregroundColor(Color(hue: self.costomHueB, saturation: 1.0, brightness: 1.0, opacity: 0.5))

Und um die Farbe ständig zu ändern, ist es notwendig, den Wert von costomHueA / B der Immobilie ständig zu ändern. Wir haben dies getan, als wir die ProgressBarView erstellt haben, aber wir können dies mit dem Modifikator onReceive tun, indem wir die timer-Eigenschaft der TimeManager-Klasse (die Veröffentlichungsmethode der Timer-Klasse) auslösen.

Erstellen Sie einen onReceive-Modifikator für den ZStack {}, der die beiden Circle-Komponenten im Body {} enthält.

Gleichzeitig mit der Aktivierung der Timer.publish-Methode alle 0,05 Sekunden wird auch der Wert von costomHueA / B um +0,05 erhöht. Da der Argumentfarbton der Farbstruktur, mit der die Farbe erstellt wird, nur den Wert Double von 0 bis 1 annimmt, fügen Sie ihn mit einer if-Anweisung hinzu, sodass er bei einem Wert von 1,0 für costomHueA / B auf 0,0 zurückkehrt.

.onReceive(timeManager.timer) { _ in
    self.costomHueA += 0.005
    if self.costomHueA >= 1.0 {
        self.costomHueA = 0.0
    }
    self.costomHueB += 0.005
    if self.costomHueB >= 1.0 {
        self.costomHueB = 0.0
    }
}

Zu diesem Zeitpunkt sieht der gesamte Code folgendermaßen aus:

AnimationView.swift


struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager
    @State var costomHueA: Double = 0.5
    @State var costomHueB: Double = 0.3

    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    
    var body: some View {
        ZStack{
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueA, saturation: 1.0, brightness: 1.0, opacity: 0.5))
         
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueB, saturation: 1.0, brightness: 1.0, opacity: 0.5))
        }
        .onReceive(timeManager.timer) { _ in
            self.costomHueA += 0.005
            if self.costomHueA >= 1.0 {
                self.costomHueA = 0.0
            }
            self.costomHueB += 0.005
            if self.costomHueB >= 1.0 {
                self.costomHueB = 0.0
            }
        }
    }
}

5. Wenden Sie eine Animation an, die die Form verschiebt

Wir werden den beiden Kreisen Modifikatoren für die Animation hinzufügen.

Drehen Sie den Kreis mit dem Modifikator "rotationseffekt". Abhängig vom Drehwinkel ändert sich auch die Position des Kreises, der durch den zuvor hinzugefügten Versatzmodifikator verschoben wurde, um den gleichen Winkel um die Bildschirmmitte.

Wenn Sie daher zwei Kreise entlang eines kreisförmigen Fortschrittsbalkens verschieben möchten, geben Sie die Winkel der beiden Muster am Anfang und Ende der Animation in () der Rotationseffektargumentgrade an und verschieben Sie die beiden in regelmäßigen Abständen. Das Umschalten bewirkt eine Änderung des Winkelwerts zwischen vor und nach dem Umschalten, und die Änderung wird in der Animation wiedergegeben. Das Ergebnis ist eine Animation von zwei Kreisen, die sich hin und her bewegen.

Hier möchten wir eine Animation erstellen, die sich um 360 ° bewegt. Geben Sie also 0 ° und 360 ° an. Bereiten Sie die Eigenschaft im Uhrzeigersinn als Bool-Typ als Auslöser zum Umschalten des Winkels vor. Belassen Sie den Anfangswert auf true.

@State var clockwise = true

Wenn die Eigenschaft im Uhrzeigersinn wahr ist, beträgt die Drehung des Kreises 0 °, und wenn sie falsch ist, beträgt die Drehung 360 °. Andererseits wird die andere Kreiskomponente umgekehrt, so dass sie im Uhrzeigersinn 360 ° und bei Falsch 0 ° beträgt. Dadurch drehen sich die beiden Kreise in entgegengesetzte Richtungen.

//Für den ersten Kreis
.rotationEffect(.degrees(clockwise ? 0 : 360))
//Für den zweiten Kreis
.rotationEffect(.degrees(clockwise ? 360 : 0))

Fügen Sie unter dem Modifikator "RotationEffect" einen Animationsmodifikator hinzu. Dadurch wird die Animation auf Modifikatoren über dem Animationsmodifikator angewendet.

Es gibt verschiedene Arten von Animationen, aber wir möchten, dass die Bewegung am Anfang langsam, in der Mitte schnell und am Ende langsam ist. Daher wenden wir hier easyInOut als Argument für den Animationsmodifikator an. Geben Sie dann 5 in das Dauer-Argument von easyInOut ein. Dies bedeutet, dass eine einzelne Animation über 5 Sekunden ausgeführt wird.

.animation(.easeInOut(duration: 5))

Das Aktivierungsintervall der Timer-Eigenschaft ist jedoch mit 0,05 Sekunden pro Stunde recht kurz. Erstellen Sie daher eine weitere count-Eigenschaft vom Typ Double. Es wird immer nur innerhalb dieser AnimationView-Struktur referenziert, daher wird dem @ Wate-Eigenschafts-Wrapper vorangestellt.

@State var count: Double = 0

Stellen Sie im in Schritt 4 erstellten Modifikator onReceive zunächst sicher, dass der Wert im Uhrzeigersinn umgeschaltet ist, wenn die Eigenschaft count 0 ist. Stellen Sie also sicher, dass die Animation startet, wenn count 0 ist.

.onReceive(timeManager.timer) { _ in
    if self.count <= 0 {
        self.clockwise.toggle()
    }

    //(Ausgelassener Code für costomHue)
}

Schreiben Sie außerdem Code, der den Wert der count-Eigenschaft im Laufe der Zeit ändert.

Da die Timer.publish-Methode alle 0,05 Sekunden ausgelöst wird, erhöht sie auch den Wert der count-Eigenschaft um 0,05 Sekunden. Wenn der Wert der count-Eigenschaft 5 erreicht, sollte der Wert der count-Eigenschaft wieder auf 0 zurückgesetzt werden.

.onReceive(timeManager.timer) { _ in
    if self.count <= 0 {
        self.clockwise.toggle()
    }
    if self.count < 5.00 {
        self.count += 0.05
    } else {
        self.count = 0
    }
    //(Ausgelassener Code für costomHue)
}

Dadurch wird die Eigenschaft im Uhrzeigersinn alle 5 Sekunden umgeschaltet und die Animation ausgelöst. Die für jede Animation erforderliche Zeit ist ebenfalls auf 5 Sekunden eingestellt, sodass die Animation alle 5 Sekunden ohne Unterbrechung wiederholt wird.

Jetzt sieht der gesamte Code folgendermaßen aus: Damit ist die Animationsansicht abgeschlossen.

AnimationView.swift


struct AnimationView: View {
    @EnvironmentObject var timeManager: TimeManager
    @State var costomHueA: Double = 0.5
    @State var costomHueB: Double = 0.3
    @State var clockwise = true

    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    
    var body: some View {
        ZStack{
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueA, saturation: 1.0, brightness: 1.0, opacity: 0.5))
                .rotationEffect(.degrees(clockwise ? 0 : 360))
                .animation(.easeInOut(duration: 5))
            
            Circle()
                .frame(width: 20, height: 20)
                .offset(y: -self.screenWidth * 0.38)
                .foregroundColor(Color(hue: self.costomHueB, saturation: 1.0, brightness: 1.0, opacity: 0.5))
                .rotationEffect(.degrees(clockwise ? 360 : 0))
                .animation(.easeInOut(duration: 5))
        }
        .onReceive(timeManager.timer) { _ in
            if self.count <= 0 {
                self.clockwise.toggle()
            }
            if self.count < 5.00 {
                self.count += 0.05
            } else {
                self.count = 0
            }
            
            self.costomHueA += 0.005
            if self.costomHueA >= 1.0 {
                self.costomHueA = 0.0
            }
            self.costomHueB += 0.005
            if self.costomHueB >= 1.0 {
                self.costomHueB = 0.0
            }
        }
    }
}

Überprüfen Sie die Animationsansicht auf Leinwand. Es sollte wie im GIF-Bild unten aussehen. 5p2wx-8k3l6.gif

6. Platzieren Sie die animierte Ansicht in der Hauptansicht

Platzieren wir nun die fertige Animationsansicht in der Hauptansicht.

Die Animationsanzeigebedingung wird nur festgelegt, wenn der Timer-Status nicht gestoppt ist (.running oder .pause).

Darüber hinaus gibt es in den zuvor erstellten Einstellungselementen der SettingView einen Ein / Aus-Kippschalter für die Effektanimation. Daher wird die Animation nur angezeigt, wenn isEffectAnimationOn der TimeManager-Klasse, die mit diesem Kippschalter verknüpft ist, true ist.

Beschreiben Sie mit einer if-Anweisung unter den beiden oben genannten Bedingungen.

if timeManager.isEffectAnimationOn && timeManager.timerStatus != .stopped {
    AnimationView()
}

Außerdem möchte ich die Animationsansicht im Code auf der Ebene nach dem oberen Fortschrittsbalken platzieren, damit ich sie am Anfang von ZStack {} schreibe.

Schließlich sieht der Code für MainView folgendermaßen aus:

MainView


struct MainView: View {
    @EnvironmentObject var timeManager: TimeManager
    
    var body: some View {
        ZStack {
            if timeManager.isEffectAnimationOn && timeManager.timerStatus != .stopped {
                AnimationView()
            }
            
            if timeManager.isProgressBarOn {
                ProgressBarView()
            }
            
            //(Andere Ansichten weggelassen)
        }
        .onReceive(timeManager.timer) { _ in
            //(Kürzung)
        }
    }
}

Überprüfen Sie die Hauptansicht in Canvas. Es sollte wie im Bild unten aussehen. スクリーンショット 2020-10-28 11.44.42.png

schließlich

Diese "iOS App Development: Timer App" -Serie ist mit allen 10 bisherigen Artikeln abgeschlossen.

Ich habe in der App keine Schaltflächen, Texte oder Hintergrundfarben angegeben, daher fehlt möglicherweise die Farbe. Wenn Sie auf die Artikel in dieser Reihe verweisen möchten, versuchen Sie bitte, sie selbst anzupassen.

Recommended Posts

iOS App Entwicklung: Timer App (10. Animation erstellen)
iOS App Entwicklung: Timer App (2. Timer Anzeige)
iOS App Entwicklung: Timer App (Zusammenfassung)
iOS App Entwicklung: Timer App (1. Timer Zeiteinstellung)
Entwicklung der iOS-App: Timer-App (3. Start / Stopp-Taste, Reset-Taste)
iOS App Entwicklung: Timer App (7. Implementierung der Alarmtonauswahl)
iOS App Entwicklung: Timer App (5. Implementierung von Alarm und Vibration)
Entwicklung der iOS-App: Timer-App (9. Passen Sie die Farbe des Fortschrittsbalkens an)
Roadmap für die Entwicklung von iOS-Apps (Einführung)
Der iOS-Ingenieur startet die Android-Entwicklung
ROS App Entwicklung auf Android
ATDD-Entwicklung unter iOS (Basic Edition)