Adapter votre solution commerciale existante pour SwiftUI. Partie 1

Bonne journée à tous. Je m'appelle Anna Zharkova, je suis l'un des principaux développeurs mobiles d' Usetech à

propos de la technologie SwiftUI, qu'Apple a annoncé l'année dernière à la WWDC 2019, beaucoup de choses ont été dites. En principe, il y a déjà suffisamment de matériel sur ses fonctionnalités, ce qui se trouve sous son capot et comment l'utiliser pour une interface utilisateur rapide et belle.



Je vous propose une courte série d'articles sur la façon d'utiliser ce cadre dans la vie réelle et les applications réelles, et non dans les constructeurs de sandwichs d'avocat. Et pour que tout soit sérieux et mature, nous verrons comment rendre notre application SwiftUI conforme aux principes de l'architecture propre et du code propre.

Mais commençons par les bases. Cette partie ne sera qu'une introduction et des informations de base. Donc, si vous êtes déjà familier avec ces fonctionnalités SwiftUI, passez aux parties suivantes:
partie 2 (comment travailler avec des bibliothèques prêtes à l'emploi sous UIKit)
partie 3 (ici à propos de l'architecture)
partie 4 (ici à propos de la navigation)

Si vous ne vous connaissez pas encore, alors attardez-vous quelques minutes)

Les principales caractéristiques du développement déclaratif dans le nouveau cadre s'écartent de l'utilisation directe de UIViewController, UIView et le remplacement par des structures qui implémentent le protocole View. Tous les composants de la partie visuelle sont également décrits à l'aide de la syntaxe déclarative et se trouvent à l'intérieur de la propriété de corps principal de chaque vue. Paramètres, stylisation et personnalisation des composants, la navigation entre les vues à l'écran est également définie à l'aide de la syntaxe déclarative.

Par exemple, ce code décrit une vue pour une liste de nouvelles, en cliquant sur lequel un écran s'ouvre avec une vue de nouvelles distincte:

struct NewsListView: View{
    @State var data: [NewsItemMock]
    
    var body: some View {
        NavigationView{
        List(data) { item in
            NavigationLink(destination:NewsItemView(item:item)) {
            NewsItemRow(data: item)
            }
        }
    }
}

SwiftUI utilise ViewBuilder, un concepteur d'interface déclarative basé sur Functional Builder. Ce mécanisme est apparu dans Swift 5.1 et vous permet de regrouper des éléments dans un certain tableau à l'intérieur d'un bloc de fermeture, par exemple, un objet parent. Un exemple d'utilisation de ViewBuilder est présenté sur la diapositive. Nous plaçons simplement les contrôles View dans l'ordre dont nous avons besoin, par exemple, à l'intérieur d'une pile verticale ou horizontale, sans utiliser addSubview, et lors de la compilation de SwiftUI lui-même, il ajoute et regroupe des éléments dans un conteneur parent plus complexe.

Et voici le code:


          VStack {
            HStack {
                VStack(alignment: .leading,spacing: 10) {
                    HeaderText(text: data.title ?? "")
                    SubheaderText(text: data.description ?? "")
                    SmallText(text: data.publishedAt?
                                   .formatToString("dd.MM.yyyy") ?? "")
                }
               ThumbImage(withURL: data.urlToImage ?? "")
             }

converti en un élément de liste de 3 champs de texte et une image:


Bien que SwiftUI nie le concept d'un UIViewController, le point d'entrée de l'application est le UIHostingController, dans lequel la vue affichée est passée et incorporée. En fait, la nouvelle technologie est un complément à UIKit:


@available(iOS 13.0, tvOS 13.0, *)
open class UIHostingController<Content> : UIViewController where Content : View {

    public var rootView: Content

    public init(rootView: Content)


Soit dit en passant, tous les contrôles SwiftUI sont des analogues déclaratifs des contrôles UIKit.

Par exemple, VStack, HStack sont des analogues de l'UIStackView vertical et horizontal habituel, respectivement. La liste est UITableView, le texte est UILabel, le bouton est UIButton, l'image est UIImage, etc.

La connexion et la configuration des contrôles se font de manière déclarative à l'aide des modificateurs disponibles. Les éléments sont regroupés dans des analogues UIStackView avec certaines propriétés prédéfinies.

En plus de changer la façon dont la partie visuelle est décrite, le contrôle du flux de données et le mécanisme de la réaction de l'interface utilisateur changent. L'interface utilisateur rapide est un cadre non dépendant des événements. Ceux. La vue est le résultat d'une fonction de certains états, et non d'une séquence d'événements. L'action effectuée par l'utilisateur ne modifie pas directement l'interface utilisateur, vous ne pouvez pas modifier directement telle ou telle vue, ajouter ou supprimer des contrôles. Tout d'abord, les propriétés ou les variables d'état connectées à la vue via l'un ou l'autre des wrappers de propriété (wrappers de propriété) changent .



Les principaux wrappers de propriétés utilisés sont:

1.Etat - utilisé pour les variables locales.


struct NewsItemRow: View {
    @State var title: String
    @State var  description: String
    @State var dateFormatted: String 
    @State var imageUrl: String 
    
    var body: some View {
        VStack {
            HStack {
                VStack(alignment: .leading,spacing: 10) {
                    HeaderText(text: title)
                    SubheaderText(text: description)
                    SmallText(text: dateFormatted)
                }
              ThumbImage(withURL: imageUrl)
            }
         }
     }

2. @Binding - un analogue de faible, utilisé lors du passage d'une référence à une valeur.

Nous l'utilisons lorsque plusieurs vues dépendent d'une propriété. Par exemple, si nous voulons transmettre la valeur à la vue d'origine à partir de la vue du deuxième niveau.


struct FirstView: View {
    @State var isPresented: Bool = true
    
    var body: some View {
        NavigationView {
            NavigationLink(destination:
            SecondView(isPresented: self.$isPresented)) {
                Text("Some")
            }
        }
    }
}

struct SecondView: View {
    @Binding var isPresented: Bool
    
    var body: some View {
        Button("Dismiss") {
            self.$isPresented = false
        }
    }
}

3. @EnvironmentObject - transfert d'objets entre View

4. @ObjectBinding, @ObservableObject - utilisé pour suivre les modifications des propriétés du modèle à l'aide des outils de structure Combine.


class NewsItemModel: ObservableObject,IModel {
   @Published var title: String
   @Published var  description: String
   @Published var dateFormatted: String 
   @Published var imageUrl: String 
}

Nous parlerons de lui plus tard.

Donc. Si nous voulons changer notre vue, nous changeons la propriété, une annonce avec l'un des Property Wrappers. Ensuite, la vue déclarative est reconstruite avec tous les contrôles internes.
Lorsque l'une des variables d'état change, la vue est reconstruite dans son ensemble.

Prenons un petit exemple. Nous avons une sorte d'écran, dans la barre de navigation dont il y a un bouton pour ajouter du contenu aux favoris. Afin de changer l'image de l'indicateur sur ce bouton, nous utiliserons PropertyWrappers. Par exemple, dans ce cas, créez une variable locale et déclarez-la commeEtat:


struct NewsItemView: View {
@State var isFavorite: Bool 
....

Nous assignerons la modification de la valeur de la propriété à l'événement déclencheur qui se produit lorsque le bouton est enfoncé:

struct NewsItemView: View{
    @State var isFavorite: Bool 
   
    var body: some View {
    NavigationView {
    VStack {
        Text("Some content")
       }
    }
     .navigationBarItems(trailing: Button(action: {
            self.isFavorite = !self.isFavorite
        }){
            Image(self.isFavorite ? "favorite" : "unfavorite")
           .frame(width: 20, height: 20, alignment: .topTrailing)
        })
   }
        

Ainsi, notre point de vue va changer:



et en principe, ce sont toutes les choses de base que vous devez savoir sur SwiftUI pour commencer.

Mais est-ce suffisant pour fonctionner?

Pour créer des interfaces utilisateur simples à partir de contrôles simples sans être lié à Xib et aux storyboards, complètement.

Et pour quelque chose de plus, non.

Premièrement, tous les contrôles n'ont pas d'analogues dans SwiftUI. Cela s'applique à la fois à UIKit UISearchView standard, à UICollectionView et aux éléments des bibliothèques tierces.

Deuxièmement, il n'existe pas (ou presque aucune, peut-être que quelqu'un le fait actuellement) de solutions tierces pour travailler avec Data Flow SwiftUI.

Vous devez donc adapter les solutions existantes aux applications iOS standard.

Veuillez cliquer sur le lien.

All Articles