Faisons des cartes animées avec prise en charge des gestes sur SwiftUI
:
Je voulais ajouter un aperçu détaillé, mais la taille du gif n'est pas orthodoxe. Un grand aperçu peut être consulté sur le lien ou dans le didacticiel vidéo .
Sera nécessaire
SwiftUI
maintenant en version bêta et est installé avec le nouveau Xcode, qui est également en version bêta. La bonne nouvelle est que le nouveau Xcode peut être placé à côté de l'ancien et que vous ne ressentez pratiquement aucune douleur.

Vous pouvez le télécharger à partir du lien dans la section Applications
.
Vous avez peut-être vu des aperçus en temps réel lorsque vous travailliez avec SwiftUI
. Pour l'activer, ainsi que certains menus contextuels, vous devez installer la beta macOS Catalina
. Cela ne se fera pas sans douleur. Je n'ai pas parié, donc je vais exécuter le simulateur à l'ancienne.
Nouveau projet
Créer une Single View Application
avec une coche supplémentaire - SwiftUI
:
Accédez au fichier ContentView.swift . L'héritier de PreviewProvider
est responsable de l'aperçu. Puisque nous ne l'utiliserons pas, nous laisserons le code minimum nécessaire:
import SwiftUI struct ContentView: View { var body: some View { } }
J'espère qu'il y a déjà une compréhension commune de SwiftUI
, nous ne nous attarderons pas sur des points triviaux.
Les cartes
Les cartes sont disposées les unes après les autres, nous utiliserons donc ZStack
. Permettez-moi de vous rappeler qu'il existe deux autres options de regroupement des éléments: HStack
- horizontalement et VStack
- verticalement. Pour plus de clarté:

Ajoutez la première carte:
struct ContentView: View { var body: some View { return ZStack { Rectangle() .fill(Color.black) .frame(height: 230) .cornerRadius(10) .padding(16) } } }
Ici, nous avons ajouté un rectangle, peint en noir, 230pt
hauteur, arrondi les bords de 10 10pt
et réglé les marges de tous les côtés à 16pt
.
Le texte de la carte est ajouté au bloc ZStack
après le rectangle:
Text("Main Card") .color(.white) .font(.title) .bold()
Exécutez le projet pour voir le résultat intermédiaire:
Mais il y en a trois!

Pour plus de commodité, nous MainCard
code MainCard
:
struct MainCard: View { var title: String var body: some View { ZStack { Rectangle() .fill(Color.black) .frame(height: 230) .cornerRadius(10) .padding(16) Text(title) .color(.white) .font(.largeTitle) .bold() } } }
Le title
apparaîtra dans l'initialiseur. Ce texte sera sur la carte. Ajoutez une carte au ContentView
, en même temps nous verrons un nouveau paramètre dans l'initialiseur:
struct ContentView: View { var body: some View { return MainCard(title: "Main Card") } }
Nous savons déjà comment créer le code, alors définissez immédiatement une classe pour les cartes d'arrière-plan:
struct Card: View { var title: String var body: some View { ZStack { Rectangle() .fill(Color(red: 68 / 255, green: 41 / 255, blue: 182 / 255)) .frame(height: 230) .cornerRadius(10) .padding(16) Text(title) .color(.white) .font(.title) .bold() } } }
Définissez une couleur et un style différents pour le texte. Le reste du code répète la MainCard
noire principale. Ajoutez deux cartes d'arrière-plan à ContentView
. Les cartes sont disposées les unes après les autres, nous les ZStack
dans ZStack
. Code ContentView
:
struct ContentView: View { var body: some View { return ZStack { Card(title: "Third card") Card(title: "Second Card") MainCard(title: "Main Card") } } }
Les cartes d'arrière-plan sont situées sous le noir et jusqu'à présent, elles ne sont pas visibles. Ajoutez un décalage vers le haut et un rembourrage à partir des bords:
Card(title: "Third card") .blendMode(.hardLight) .padding(64) .padding(.bottom, 64) Card(title: "Second Card") .blendMode(.hardLight) .padding(32) .padding(.bottom, 32) MainCard(title: "Main Card")
Maintenant, le résultat ressemble à l'annonce au début du tutoriel:
Passons aux gestes, et en même temps aux animations.
Gestes
La façon dont les gestes sont mis en œuvre me forcera à diminuer le karma et à laisser un avis toxique.

Avant de voir le code, veuillez noter - il est répertorié sur developer.apple.com à titre d'exemple. La première impression est trompeuse, en pratique j'ai bien aimé.
Déclarez l'énumération dans ContentView
:
enum DragState { case inactive case dragging(translation: CGSize) var translation: CGSize { switch self { case .inactive: return .zero case .dragging(let translation): return translation } } var isActive: Bool { switch self { case .inactive: return false case .dragging: return true } } }
DragState
rendra le travail avec un geste plus confortable. Ajoutez des dragState
dragState à ContentView
:
@GestureState var dragState = DragState.inactive
Il y aura de la magie.

Partout où dragState
sera utilisé, les nouvelles valeurs seront appliquées automatiquement. Déclarez un geste:
let dragGester = DragGesture() .updating($dragState) { (value, state, transaction) in state = .dragging(translation: value.translation) }
Ajoutez un geste à la carte principale et définissez le offset
:
MainCard(title: "Main Card") .offset( x: dragState.translation.width, y: dragState.translation.height ) .gesture(dragGester)
Le décalage sera-t-il égal à la valeur du paramètre lors de son accès? Non, ce sera toujours égal . C'est magique.
La carte suivra avec un doigt avec une souris, mais sans animations:
Les cartes de fond devraient également changer leur position ( au moins nous le voulions ). Ajoutez pour eux du code lié à l'état du geste. rotation3DEffect
fera tourner la carte jusqu'à ce que le geste devienne actif:
Card(title: "Third card") .rotation3DEffect(Angle(degrees: dragState.isActive ? 0 : 60), axis: (x: 10.0, y: 10.0, z: 10.0)) .blendMode(.hardLight) .padding(dragState.isActive ? 32 : 64) .padding(.bottom, dragState.isActive ? 32 : 64) Card(title: "Second Card") .rotation3DEffect(Angle(degrees: dragState.isActive ? 0 : 30), axis: (x: 10.0, y: 10.0, z: 10.0)) .blendMode(.hardLight) .padding(dragState.isActive ? 16 : 32) .padding(.bottom, dragState.isActive ? 0 : 32)
Sinon, comment pouvez-vous utiliser la 3D, vous pouvez regarder ici . J'ai également ajouté blendMode
. Les modes sont similaires aux outils de Photoshop et Sketch.
Bien que les modifications soient appliquées et non animées, corrigeons-le.
L'animation
Vous serez surpris de voir à quel point c'est simple. Ajoutez simplement une ligne:
.animation(.spring())
Ajoutez pour chaque carte. Maintenant, toutes les modifications seront appliquées de manière animée, dans notre cas, il s'agit des tailles d'indentation, de la rotation 3D et du offset
. Si vous avez besoin d'une animation avec des courbes, utilisez basic
mode de basic
.
Décorations
Ajoutez l'ombre et la rotation de la vue principale, liées au décalage:
.rotationEffect(Angle(degrees: Double(dragState.translation.width / 10))) .shadow(radius: dragState.isActive ? 8 : 0)
Si vous exécutez le projet, vous verrez la référence depuis le début du didacticiel. Activer l'aperçu n'est pas visible, tirez la carte sur le côté pour voir l'effet.
Pour les demandeurs
→ Le code du projet se trouve dans le référentiel
Il suffit de copier le fichier dans le projet, aucun paramètre supplémentaire n'est requis. N'ayez pas peur que si peu de code soit l'un des SwiftUI
de SwiftUI
.
S'il vous est plus pratique de regarder la vidéo, jetez un œil au didacticiel. Soit dit en passant, dans la vidéo, j'utilise des aperçus en temps réel.