[SWIFT] Développement d'applications iOS: application Timer (6. Création de l'écran de réglage)

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

article

Les points pour créer une application de minuterie sont publiés dans plusieurs articles. Dans cet article, je vais vous montrer comment créer un écran de réglage qui comprend l'activation / la désactivation du son de l'alarme et l'activation / la désactivation de la barre de progression.

environnement

Dépôt Git

Vous pouvez voir l'exemple de code à partir de l'URL du référentiel Git suivante. https://github.com/msnsk/Qiita_Timer.git

procédure

  1. Liste des éléments de réglage
  2. Créez SettingView
  3. Créez une liste dans SettingView
  4. Ajoutez l'élément de réglage à la liste de SettingView
  5. Ajoutez les propriétés requises pour divers paramètres à TimeManager
  6. Associez les paramètres SettingView aux propriétés TimeManager
  7. Rendre SettingView modal
  8. Ajoutez un bouton de réglage à MainView et affichez l'écran de réglage de manière modale

Procédure détaillée

1. Liste des éléments de réglage

Nous allons créer un écran de réglage. Le PickerView, TimerView et ButtonsView que j'ai créés jusqu'à présent sont tous placés dans MainView et l'application de minuterie n'a pas d'écran autre que MainView.

Cette fois, nous allons créer un écran de réglage séparément de MainView. Les éléments suivants seront affichés sur cet écran de réglage.

2. Créez une vue des paramètres

À partir du modèle SwiftUI, créez un nouveau fichier nommé SettingView.

Encore une fois, les informations de paramètres seront éventuellement reflétées dans les propriétés de la classe TimeManager, alors ajoutez d'abord le wrapper de propriété @EnvironmentObject pour créer une instance de TimeManager.

SettingView.swift


import SwiftUI

struct SettingView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        Text("Hello, World!")
    }
}

3. Créez une liste dans SettingView

Il existe deux principaux types de composants utilisés dans l'affichage de liste dans SwiftUI. L'un est la liste et l'autre la forme.

Form est utilisé pour l'écran de configuration des applications iOS générales, donc cette fois, nous utiliserons Form.

À propos, même si vous divisez certaines sections avec des titres, la liste sera affichée avec toutes les sections, y compris les divisions de section séparées par des bordures, il est donc plus approprié pour organiser des éléments tels que des rappels dans une ligne. ..

En ce qui concerne l'élément de sélection du son d'alarme, nous voulons passer de l'écran de réglage à l'écran de sélection du son, donc placez le composant Form dans le NavigationView. En faisant cela, il est possible de configurer la transition à partir du formulaire vers une autre liste ou formulaire.

SettingView.swift


struct SettingView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        NavigationView {
            Form {
            }
        }
    }
}

4. Ajoutez l'élément de réglage à la liste de SettingView

La configuration de l'écran est supposée comme suit.

Section 1: Alarme liée </ strong>

  • Interrupteur à bascule marche / arrêt du son de l'alarme
  • Interrupteur à bascule marche / arrêt de vibration --Sélection du son d'alarme

Section 2: Animation </ strong>

  • Interrupteur à bascule marche / arrêt de l'affichage de la barre de progression
  • Interrupteur à bascule marche / arrêt de l'animation d'effet
  • La mise en œuvre réelle de la section 2 sera effectuée après la création de l'écran de réglage.

Section 3: Fermez l'écran des paramètres </ strong> --Bouton pour fermer l'écran de réglage

Mettez trois sections dans le formulaire. La première section contient deux Toggle et un NavigationLink. Mettez un Toggle dans la deuxième section. Mettez un bouton dans la troisième section.

Si vous mettez le titre de la section dans Texte dans l'en-tête d'argument de Section, il sera plus facile de comprendre de quelle section il s'agit.

SettingView.swift


struct SettingView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Alarm:")) {
                    Toggle(isOn: ) {
                    }
                    Toggle(isOn: ) {
                    }
                    NavigationLink(destination: )) {
                    }
                }
                Section(header: Text("Animation:")) {
                    Toggle(isOn: ) {
                    }
                    Toggle(isOn: ) {
                    }
                }
                Section(header: Text("Save:")) {
                    Button(action: ) { 
                    }
                }
            }
        }
    }
}

Nous avons maintenant besoin d'une propriété pour refléter l'activation / la désactivation du composant Toggle. Cette propriété doit être reflétée dans chaque composant de MainView à partir de l'écran des paramètres. Par exemple, si vous activez une alarme sur l'écran des paramètres, le paramètre sera en fait déclenché dans MainView.

Par conséquent, la propriété qui stocke chaque information de paramètre doit être ajoutée à la classe TimeManager avec le wrapper de propriété @Published.

5. Ajoutez les propriétés requises pour divers paramètres à TimeManager

Ajoutez quatre propriétés à TimeManager pour stocker les informations de configuration du commutateur à bascule. Les quatre éléments suivants seront ajoutés.

  • Réglage marche / arrêt du son de l'alarme
  • Réglage marche / arrêt de la vibration
  • Réglage marche / arrêt de l'affichage de la barre de progression
  • Paramètre d'activation / désactivation de l'affichage de l'animation

TimeManager.swift


class TimeManager: ObservableObject {
    //(Autres propriétés omises)

    //Stocke le nom du son correspondant à la valeur de la propriété soundID
    @Published var soundName: String = "Beat"

    //Son d'alarme activé/Réglage Off
    @Published var isAlarmOn: Bool = true
    //Vibration sur/Réglage Off
    @Published var isVibrationOn: Bool = true
    //Affichage de la barre de progression sur/Réglage Off
    @Published var isProgressBarOn: Bool = true
    //Affichage de l'animation d'effet sur/Réglage Off
    @Published var isEffectAnimationOn: Bool = true

    //La méthode de publication de la classe Timer qui est activée toutes les secondes
    var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    //(Méthode omise)
}

6. Associez les paramètres SettingView aux propriétés TimeManager

Dans l'argument de méthode Toggle isOn, spécifiez la propriété du TimeManager pour laquelle vous souhaitez stocker les paramètres. À ce stade, vous devez le préfixer avec le symbole $. En outre, dans la fermeture, entrez le nom que vous souhaitez afficher comme élément de réglage dans le formulaire avec texte.

Toggle(isOn: $timeManager.isAlarmOn) {
         Text("Alarm Sound")
 }

De cette façon, nous décrirons tous les arguments et fermetures Toggle pour le moment.

En ce qui concerne l'élément de sélection du son d'alarme, il n'y a pas encore d'écran de sélection, alors commentez-le une fois.

L'étiquette du dernier bouton d'enregistrement est fournie avec du texte et une icône de coche. Puisque nous voulons le placer au centre dans le sens horizontal, nous l'amènerons au centre en l'entourant de HStack et en plaçant Spacer de gauche à droite. L'action lorsque vous appuyez sur le bouton est toujours vide.

SettingView.swift


struct SettingView: View {
    @EnvironmentObject var timeManager: TimeManager
    
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Alarm:")) {
                    Toggle(isOn: $timeManager.isAlarmOn) {
                        Text("Alarm Sound")
                    }
                    Toggle(isOn: $timeManager.isVibrationOn) {
                        Text("Vibration")
                    }
//                    NavigationLink(destination: ) {
//
//                    }
                }
                Section(header: Text("Animation:")) {
                    Toggle(isOn: $timeManager.isProgressBarOn) {
                        Text("Progress Bar")
                    }
                    Toggle(isOn: $timeManager.isEffectAnimationOn) {
                        Text("Effect Animation")
                    }
                }
                Section(header: Text("Save:")) {
                    Button(action: ) {
                        HStack {
                            Spacer()
                            Text("Done")
                            Image(systemName: "checkmark.circle")
                            Spacer()
                        }
                    }
                }
            }
        }
    }
}

Vérifiez l'affichage de SettingView sur le canevas. Voici le code de l'aperçu.

struct SettingView_Previews: PreviewProvider {
    static var previews: some View {
        SettingView().environmentObject(TimeManager())
    }
}

Cela devrait ressembler à l'image ci-dessous. スクリーンショット 2020-10-28 11.14.35.png

7. Rendre SettingView modal

Affichez le SettingView de manière modale. Modal est un nom abrégé pour une fenêtre modale, ce qui revient à être inopérant lorsque la fenêtre est ouverte.

Préparez une variable avec un wrapper de propriété appelé @Environment (\ .presentationMode) dans SettingView.

Ensuite, écrivez le code pour fermer le modal dans la fermeture de l'argument d'action du bouton Enregistrer qui est tapé lors de la fermeture de l'écran de réglage.

self.presentationMode.wrappedValue.dismiss()

SettingView.swift


struct SettingView: View {
    //Propriétés d'utilisation des feuilles modales
    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject var timeManager: TimeManager
    
    var body: some View {
        NavigationView {
            Form {
                //(Autres sections omises)

                Section(header: Text("Save:")) {
                    Button(action: { 
                        //Appuyez pour fermer le modal
                        self.presentationMode.wrappedValue.dismiss()
                    }) {
                        HStack {
                            Spacer()
                            Text("Done")
                            Image(systemName: "checkmark.circle")
                            Spacer()
                        }
                    }
                }
            }
        }
    }
}

Cette fois, au contraire, nous allons préparer un bouton dans MainView pour ouvrir l'écran de réglage. Avec un seul bouton, créez une vue facile à comprendre. Créons maintenant un nouveau fichier SwiftUI nommé SettingButton.

SettingButtonView.swift


import SwiftUI

struct SettingButtonView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
    }
}

L'icône du bouton utilise "ellipsis.circle.fill" de SF Symbols.

SettingButtonView.swift


import SwiftUI

struct SettingButtonView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        Image(systemName: "ellipsis.circle.fill")
    }
}

La taille du bouton de réglage est légèrement plus petite que celle du bouton de démarrage / pause et du bouton de réinitialisation, utilisez donc le modificateur de cadre pour définir les tailles verticale et horizontale.

SettingButtonView.swift


import SwiftUI

struct SettingButtonView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        Image(systemName: "ellipsis.circle.fill")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 40, height: 40)
    }
}

Maintenant, créez une propriété de type Bool dans la classe TimeManager qui affiche / masque le modal. Nommez-le

TimeManager.swift


class TimeManager: ObservableObject {
    //(Autres propriétés omises)

    //Affichage de l'écran de réglage/Cacher
    @Published var isSetting: Bool = false

    //(Méthode omise)
}

Et enfin, revenez à SettingButtonView et ajoutez .onTapGesture pour que la propriété isSetting de TimeManager soit vraie à l'intérieur de la fermeture {}.

SettingButtonView.swift


import SwiftUI

struct SettingButtonView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        Image(systemName: "ellipsis.circle.fill")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 40, height: 40)
            .onTapGesture {
                self.timeManager.isSetting = true
    }
}

Vérifions l'écran avec Canvas. Voici le code de l'aperçu.

struct SettingButton_Previews: PreviewProvider {
    static var previews: some View {
        SettingButtonView()
            .environmentObject(TimeManager())
            .previewLayout(.sizeThatFits)
    }
}

Cela devrait ressembler à l'image ci-dessous. スクリーンショット 2020-10-28 10.56.37.png

8. Ajoutez un bouton de réglage à MainView et affichez l'écran de réglage de manière modale

Ajoutons maintenant SettingButtonView à ManiView.

L'endroit à ajouter est le même en bas de l'écran que les boutons de démarrage / pause et de réinitialisation sous PickerView et TimerView. Par conséquent, dans ZStack {}, ButtonsView et SettingButtonView sont superposés. Peu importe quel est l'avant ou l'arrière.

SettingBottonView ajoute un modificateur de remplissage (.bottom) ainsi que ButtonsView, car il est préférable que tous les boutons soient alignés dans le sens vertical.

Ajoutez ensuite un modificateur .sheet () pour afficher la fenêtre modale. L'argument isPresented spécifie une propriété de type Bool dont le modal est affiché lorsqu'il est vrai. En d'autres termes, il s'agit de la propriété isSetting de la classe TimeManager préparée précédemment.

Dans la fermeture {}, décrivez la vue que vous souhaitez afficher de manière modale. Ici, c'est SettingView (). À ce stade, assurez-vous de décrire également la propriété .environmentObject (self.timeManager).

MainView.swift


struct MainView: View {
    @EnvironmentObject var timeManager: TimeManager
    
    var body: some View {
        ZStack {
            if timeManager.timerStatus == .stopped {
                PickerView()
            } else {
                TimerView()
            }
            
            VStack {
                Spacer()
                //Boutons de superpositionView et SettingButtonView en couches
                ZStack {
                    ButtonsView()
                        .padding(.bottom)
                    //Bouton de réglage ajouté
                    SettingButtonView()
                        .padding(.bottom)
                        //Afficher SettingView de manière modale lorsque la propriété isSetting est true
                        .sheet(isPresented: $timeManager.isSetting) {
                            SettingView()
                                            .environmentObject(self.timeManager)
                        }
                }
            }
        }
        //(.partie modificateur osReceive omise)
    }
}

Puisque nous avons ajouté des éléments de réglage du son d'alarme et des vibrations, nous émettrons une alarme lorsque la minuterie au plus près du modificateur onReceive de MainView atteint 0, et décrivons la description pour activer la vibration si le paramètre est activé. Il s'agit simplement d'un branchement conditionnel dans l'instruction if en fonction des valeurs des propriétés isAlarmOn et isVibrationOn de la classe TimeManager.

MainView.swift


struct MainView: View {
    @EnvironmentObject var timeManager: TimeManager
    
    var body: some View {
        ZStack {
            //(Voir la description omise)
        }
        //Exécute le code dans la fermeture déclenchée par une minuterie qui s'active à chaque heure spécifiée (1 seconde)
        .onReceive(timeManager.timer) { _ in
            //L'état de la minuterie est.Ne rien faire sauf courir
            guard self.timeManager.timerStatus == .running else { return }
            //Si le temps restant est supérieur à 0
            if self.timeManager.duration > 0 {
                //Du temps restant-0.05
                self.timeManager.duration -= 0.05
                //Lorsque le temps restant est égal ou inférieur à 0
            } else {
                //État de la minuterie.Changer pour arrêté
                self.timeManager.timerStatus = .stopped
                //Sonner une alarme
                if timeManager.isAlarmOn {
                    AudioServicesPlayAlertSoundWithCompletion(self.timeManager.soundID, nil)
                }
                //Activer la vibration
                if timeManager.isVibrationOn {
                    AudioServicesPlayAlertSoundWithCompletion(SystemSoundID(kSystemSoundID_Vibrate)) {}
                }
            }
        }
    }
}

Vérifions MainView avec Canvas. Voici le code de l'aperçu.

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            MainView().environmentObject(TimeManager())
        }
    }
}

Cela devrait ressembler à l'image ci-dessous. Le bouton de réglage est placé entre le bouton de démarrage et le bouton de réinitialisation avec la même hauteur. スクリーンショット 2020-10-28 10.57.44.png

Maintenant, lorsque vous appuyez sur le bouton de réglage, l'écran de réglage s'affiche de manière modale. Veuillez le vérifier avec Canvas.

Cette fois, j'ai créé une vue avec uniquement des boutons de réglage en tant que SettingButtonView, mais je pense que c'est correct de la mettre ensemble dans la ButtonsView créée précédemment.

Recommended Posts