Composants animés avec UIKit Dynamics Partie 2

introduction

Dans le premier tutoriel de cette courte série sur UIKit Dynamics, nous avons appris les bases de l'API en créant un composant de menu animé. Dans ce tutoriel, nous allons continuer à travailler sur notre projet et à implémenter un autre composant animé, une vue d'alerte personnalisée..

1. Vue d'ensemble

La vue d'alerte par défaut sur iOS est excellente, mais elle n'est pas très personnalisable en termes d'apparence et de comportement. Si vous avez besoin d'une vue d'alerte personnalisable, vous devez créer votre propre solution. C'est ce que nous allons faire dans ce tutoriel. Ce didacticiel est axé sur le comportement de la vue des alertes et non sur sa fonctionnalité. Voyons ce que le résultat est que nous sommes après

La vue d'alerte sera un UIView instance à laquelle nous allons ajouter les sous-vues suivantes:

  • une UILabel objet pour afficher le titre de la vue d'alerte
  • une UILabel objet pour afficher le message de la vue d'alerte
  • un ou plus UIButton instances permettant à l'utilisateur d'interagir avec l'affichage des alertes

Nous allons utiliser le UISnapBehavior classe pour présenter la vue d'alerte. Comme son nom l'indique, cette UIDynamicBehavior la sous-classe oblige un élément dynamique à s'accrocher à un point comme s'il était magnétiquement attiré.

le UISnapBehavior classe définit une propriété supplémentaire, amortissement, qui définit la quantité d'oscillation lorsque l'élément dynamique a atteint le point auquel il est attiré.

Nous allons utiliser un comportement de gravité, en combinaison avec un comportement de collision et de poussée, pour ignorer l'affichage des alertes. Rappelez-vous que nous avons déjà utilisé ces comportements dans le précédent tutoriel..

La vue d'alerte s'animera à partir du haut de l'écran. Lorsque la vue d'alerte est sur le point d'apparaître, le comportement d'accrochage la rendra visible et alignée au centre de l'écran. Pour ignorer l'affichage des alertes, un comportement de poussée le poussera brièvement vers le bas de l'écran et un comportement de gravité le tirera ensuite vers le haut de l'écran et le fera s'animer hors écran..

Nous allons créer une méthode d'initialisation personnalisée pour le composant vue d'alerte qui accepte le titre, le message, les titres des boutons et la vue parent de l'alerte. Nous n'implémenterons pas de protocole de délégué pour l'affichage des alertes. Au lieu de cela, nous allons utiliser des blocs, ce qui en fait une solution plus élégante et moderne. Le bloc ou le gestionnaire acceptera deux paramètres, l’index et le titre du bouton tapé par l’utilisateur.

Nous allons également afficher une vue semi-transparente derrière la vue d'alerte pour empêcher l'utilisateur d'interagir avec sa vue parent tant que la vue d'alerte est visible. Commençons par examiner les propriétés de la vue des alertes et l'initialiseur personnalisé..

2. Propriétés et initialisation

Étape 1: Création de la classe de vue d'alerte

presse Commande-N sur votre clavier pour créer un nouveau fichier et sélectionner Classe Objective-C de la liste des iOS modèles. Faites-en une sous-classe de NSObject et nommez-le Composant d'alerte.

Étape 2: Déclaration des propriétés

L'étape suivante consiste à déclarer quelques propriétés privées. Ouvrir AlertComponent.m, ajoutez une extension de classe en haut et déclarez les propriétés suivantes:

@interface AlertComponent () @property (nonatomic, strong) UIView * alertView; @property (nonatomic, strong) UIView * backgroundView; @property (nonatomic, strong) UIView * targetView; @property (nonatomic, strong) UILabel * titleLabel; @property (nonatomic, strong) UILabel * messageLabel; @property (nonatomic, strong) UIDynamicAnimator * animateur; @property (nonatomic, strong) NSString * title; @property (nonatomic, strong) NSString * message; @property (nonatomic, strong) NSArray * buttonTitles; @property (nonatomic) CGRect initialAlertViewFrame; @fin

La fonction de chaque propriété apparaîtra clairement lors de la mise en œuvre du composant d'alerte. Il est temps de créer l'initialiseur personnalisé du composant..

Étape 3: initialisation

Comme je l'ai déjà mentionné, nous allons utiliser un initialiseur personnalisé pour rendre le travail avec le composant d'alerte aussi simple que possible. L'initialiseur accepte quatre paramètres, le titre de l'alerte, son message, les titres des boutons et la vue à laquelle le composant d'alerte sera ajouté, sa vue parente. Ouvrir AlertComponent.h et ajoutez la déclaration suivante:

@interface AlertComponent: NSObject - (id) initAlertWithTitle: (NSString *) title andMessage: (NSString *) message etButtonTitles: (NSArray *) buttonTitles andTargetView: (UIView *) targetView; @fin

3. Configuration de la vue des alertes

Étape 1: Déclaration des méthodes de configuration

Dans cette partie, la vue d'alerte va être configurée et toutes ses sous-vues y seront ajoutées. En outre, la vue d’arrière-plan, ainsi que l’animateur dynamique seront également configurés..

Ouvrir AlertComponent.m et déclarez les méthodes privées suivantes dans l'extension de classe privée:

@interface AlertComponent ()… - (void) setupBackgroundView; - (void) setupAlertView; @fin

Les noms de méthodes sont explicites. Commençons par implémenter le setupAlertView méthode d'abord puisque la majeure partie de la configuration de l'alerte a lieu dans cette méthode.

Étape 2: Configuration de la vue des alertes

Dans setupAlertView, nous faisons trois choses:

  • initialiser et configurer la vue d'alerte
  • initialiser et configurer les étiquettes de la vue d'alerte
  • initialiser et configurer les boutons de la vue d'alerte

Commençons par calculer la taille et la position de la vue d'alerte, comme indiqué dans l'extrait de code ci-dessous..

- (void) setupAlertView // Définit la taille de la vue des alertes. CGSize alertViewSize = CGSizeMake (250.0, 130.0 + 50.0 * self.buttonTitles.count); // Définit le point d'origine initial en fonction de la direction de la vue d'alerte. CGPoint initialOriginPoint = CGPointMake (self.targetView.center.x, self.targetView.frame.origin.y - alertViewSize.height); 

Nous commençons par définir la taille de la vue d'alerte. Pour rendre la vue d'alerte dynamique, nous ajoutons 50.0 pointe à sa hauteur pour chaque bouton. Notez également que l'origine de l'affichage des alertes est hors écran. L'étape suivante consiste à initialiser et à configurer la vue des alertes:

self.alertView = [[UIView alloc] initWithFrame: CGRectMake (initialOriginPoint.x, initialOriginPoint.y, alertViewSize.width, alertViewSize.height)]; // Couleur de fond. [self.alertView setBackgroundColor: [UIColor colorWithRed: 0.94 green: 0.94 blue: 0.94 alpha: 1.0]]; // Crée la vue d'alerte avec des coins arrondis. [self.alertView.layer setCornerRadius: 10.0]; // Définit une bordure pour la vue d'alerte. [self.alertView.layer setBorderWidth: 1.0]; [self.alertView.layer setBorderColor: [UIColor blackColor] .CGColor]; // Assigne le cadre de vue d'alerte initial à la propriété respective. self.initialAlertViewFrame = self.alertView.frame; 

En utilisant alertViewSize et initialOriginPoint, on initialise le alertView objet et définissez sa couleur d'arrière-plan. Nous arrondissons les angles de la vue d’alerte en définissant sa couchede cornerradius à 10.0, ses largeur de la bordure à 1,0, et son couleur de la bordure au noir. Nous stockons également le cadre initial de la vue d'alerte dans son initialAlertViewFrame propriété comme nous en aurons besoin plus tard.

Si Xcode vous dit qu'il ne connaît pas le alertViewde couche propriété, puis ajoutez l'instruction d'importation suivante en haut du fichier d'implémentation:

#importation  

Il est temps d'ajouter les étiquettes. Commençons par l'étiquette du titre.

// Configure l'étiquette du titre. self.titleLabel = [[UILabel alloc]] initWithFrame: CGRectMake (0.0, 10.0, self.alertView.frame.size.width, 40.0)]; [self.titleLabel setText: self.title]; [self.titleLabel setTextAlignment: NSTextAlignmentCenter]; [self.titleLabel setFont: [UIFont font nom_fichier: @ "taille Avenir-Heavy": 14.0]]; // Ajoute le titre à la vue d'alerte. [self.alertView addSubview: self.titleLabel];

La configuration de l'étiquette du message est assez similaire.

// Configure le libellé du message. self.messageLabel = [[UILabel alloc] initWithFrame: CGRectMake (0.0, self.titleLabel.frame.origin.y + self.titleLabel.frame.size.height, self.alertView.frame.size.width, 80.0)]; [self.messageLabel setText: self.message]; [self.messageLabel setTextAlignment: NSTextAlignmentCenter]; [self.messageLabel setFont: [UIFont fontWithName: @ "Avenir" size: 14.0]]; [self.messageLabel setNumberOfLines: 3]; [self.messageLabel setLineBreakMode: NSLineBreakByWordWrapping]; // Ajoute l'étiquette du message à la vue des alertes. [self.alertView addSubview: self.messageLabel];

Notez que le numberOfLines la propriété est définie sur 3 et lineBreakMode est réglé sur NSLineBreakByWordWrapping.

Les derniers boutons à configurer sont les boutons de la vue des alertes. Même si le nombre de boutons peut varier, la configuration et le positionnement des boutons sont assez simples. Nous séparons les boutons par 5 points et utiliser un pour boucle pour les initialiser.

CGFloat lastSubviewBottomY = self.messageLabel.frame.origin.y + self.messageLabel.frame.size.height; pour (int i = 0; i<[self.buttonTitles count]; i++)  UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10.0, lastSubviewBottomY + 5.0, self.alertView.frame.size.width - 20.0, 40.0)]; [button setTitle:[self.buttonTitles objectAtIndex:i] forState:UIControlStateNormal]; [button.titleLabel setFont:[UIFont fontWithName:@"Avenir" size:13.0]]; [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [button setTitleColor:[UIColor yellowColor] forState:UIControlStateHighlighted]; [button setBackgroundColor:[UIColor colorWithRed:0.0 green:0.47 blue:0.39 alpha:1.0]]; [button addTarget:self action:@selector(handleButtonTap:) forControlEvents:UIControlEventTouchUpInside]; [button setTag:i + 1]; [self.alertView addSubview:button]; lastSubviewBottomY = button.frame.origin.y + button.frame.size.height; 

Notez que chaque bouton appelle la handleButtonTap: méthode quand il est exploité. Nous pouvons déterminer quel bouton l'utilisateur a tapé en inspectant le bouton étiquette propriété.

Enfin, ajoutez la vue d'alerte à la vue cible ou parent en ajoutant la ligne suivante au bas de la méthode setupAlertView:

// Ajoute la vue d'alerte à la vue parent. [self.targetView addSubview: self.alertView];

Étape 3: Configuration de la vue d'arrière-plan

La deuxième méthode que nous devons mettre en œuvre est setupBackgroundView. La vue d'arrière-plan empêchera l'utilisateur d'interagir avec la vue parent de la vue d'alerte aussi longtemps que la vue d'alerte est affichée. Nous avons initialement mis sa alpha propriété à 0.0, ce qui signifie qu'il est transparent.

- (void) setupBackgroundView self.backgroundView = [[UIView alloc]] initWithFrame: self.targetView.frame]; [self.backgroundView setBackgroundColor: [UIColor greyColor]]; [self.backgroundView setAlpha: 0.0]; [self.targetView addSubview: self.backgroundView]; 

Étape 4: Implémentation de l'initialiseur

Avec setupAlertView et setupBackgroundView prêt à l'emploi, implémentons l'initialiseur personnalisé que nous avons déclaré précédemment.

- (id) initAlertWithTitle: (NSString *) title andMessage: (NSString *) message andButtonTitles: (NSArray *) buttonTitles etTargetView: (UIView *) targetView if (self = [super init]) // Affectez les valeurs de paramètre à local. Propriétés. self.title = title; self.message = message; self.targetView = targetView; self.buttonTitles = buttonTitles; // Configure la vue d'arrière-plan. [auto setupBackgroundView]; // Configure la vue d'alerte. [auto setupAlertView]; // Configure l'animateur. self.animator = [[UIDynamicAnimator alloc] initWithReferenceView: self.targetView];  retourner soi-même; 

Nous avons mis le Titre, message, targetView, et boutonTitres propriétés, invoquer setupBackgroundView et setupAlertView, et initialiser l'animateur dynamique en passant self.targetView comme vue de référence.

4. Affichage de la vue d'alerte

Pour afficher la vue d'alerte après son initialisation, nous devons déclarer et implémenter une méthode publique pouvant être appelée, par exemple, par le contrôleur de vue hébergeant la vue d'alerte. Ouvrir AlertComponent.h et ajoutez la déclaration de méthode suivante:

- (void) showAlertView;

Retournez à AlertComponent.m implémenter showAlertView. Comme je l'ai mentionné plus tôt dans ce tutoriel, nous utiliserons un nouveau UIDynamicBehavior sous-classe pour afficher la vue d'alerte, UISnapBehavior. Voyons comment nous utilisons cette classe dans showAlertView.

- (void) showAlertView [self.animator removeAllBehaviors]; UISnapBehavior * snapBehavior = [[UISnapBehavior alloc] initWithItem: self.alertView snapToPoint: self.targetView.center]; snapBehavior.damping = 0,8; [self.animator addBehavior: snapBehavior]; [UIView animateWithDuration: 0.75 animations: ^ [self.backgroundView setAlpha: 0.5]; ]; 

Nous commençons par supprimer tous les comportements dynamiques existants de l'animateur dynamique afin d'éviter tout conflit. N'oubliez pas que certains comportements dynamiques ne peuvent être ajoutés qu'une seule fois à l'animateur dynamique, par exemple un comportement lié à la gravité. Nous allons également ajouter d'autres comportements dynamiques pour ignorer l'affichage des alertes..

Comme vous pouvez le constater, l’utilisation d’un comportement instantané n’est pas difficile. Nous spécifions à quel élément dynamique le comportement doit être appliqué et définissons le point sur lequel l'élément dynamique doit s'accrocher. Nous définissons également le comportement amortissement propriété comme nous avons discuté plus tôt. Notez également que nous animons le alpha propriété de la vue de fond.

Pour tester l'affichage des alertes, nous devons apporter quelques modifications à la ViewController classe. Commençons par ajouter un UIButton exemple à la vue du contrôleur de vue pour afficher la vue des alertes. Ouvrir Tableau principal et faites glisser un UIButton exemple de la Bibliothèque d'objets à la vue du contrôleur de vue. Placez le bouton près du bas de la vue et donnez-lui un titre. Afficher la vue d'alerte. Ajouter une action à ViewController.h comme indiqué ci-dessous.

@interface ViewController: UIViewController - (IBAction) showAlertView: (id) expéditeur; @fin

Retournez dans le storyboard et connectez l'action du contrôleur de vue au bouton. Ouvrir ViewController.m et importer le fichier d'en-tête du Composant d'alerte classe.

#import "AlertComponent.h"

Ensuite, déclarez une propriété dans l'extension de classe privée de type Composant d'alerte et nommez-le alertComponent.

@interface ViewController () @property (nonatomic, strong) MenuComponent * menuComponent; @property (nonatomic, strong) AlertComponent * alertComponent; - (void) showMenu: (UIGestureRecognizer *) gestureRecognizer; @fin

Nous initialisons ensuite le composant d'alerte dans le contrôleur de vue. viewDidLoad méthode.

- (void) viewDidLoad … // Initialiser le composant d'alerte self.alertComponent = [[AlertComponent alloc] initAlertWithTitle: @ "Alerte personnalisée" et Message: @ "Vous avez un nouveau message électronique, mais je ne sais pas de qui." andButtonTitles: @ [@ "Show me", @ "Je ne m'en soucie pas", @ "Pour moi, vraiment?"] andTargetView: self.view]; 

Pour afficher le composant d'alerte, appelez showAlertView: dans l'action que nous venons de créer, showAlertView:.

- (IBAction) showAlertView: (id) expéditeur [self.alertComponent showAlertView]; 

Exécutez votre application et appuyez sur le bouton pour afficher la vue des alertes. Le résultat devrait ressembler à celui ci-dessous.

5. Masquer la vue d'alerte

Comme nous l'avons vu précédemment, le handleButtonTap: Cette méthode est appelée lorsque l'utilisateur appuie sur un bouton de la vue des alertes. La vue d'alerte devrait se cacher lorsque vous appuyez sur l'un des boutons. Voyons comment cela fonctionne.

Revisiter AlertComponent.m et, dans l’extension de classe privée, déclarer le handleButtonTap: méthode.

@interface AlertComponent ()… - (void) handleButtonTap: (UIButton *) expéditeur; @fin

Dans cette méthode, nous créons un certain nombre de comportements dynamiques et les ajoutons à l'objet animateur dynamique. Les comportements dynamiques dont nous avons besoin sont:

  • un comportement de gravité qui tire la vue d'alerte vers le haut de l'écran
  • un comportement de collision avec une limite hors écran qui arrête l'affichage des alertes
  • un comportement push qui donne à la vue d'alerte un petit coup de pouce vers le bas de l'écran

Après avoir supprimé les comportements existants de l'animateur dynamique et initialisé le comportement de diffusion, comme indiqué ci-dessous..

- (void) handleButtonTap: (UIButton *) sender // Supprime tous les comportements de l'animateur. [self.animator removeAllBehaviors]; UIPushBehavior * pushBehavior = [[UIPushBehavior alloc]] initWithItems: @ [self.alertView] mode: UIPushBehaviorModeInstantaneous. [pushBehavior setAngle: magnitude M_PI_2: 20,0]; [self.animator addBehavior: pushBehavior]; 

le angle La propriété du comportement de poussée définit la direction de la poussée. En définissant l'angle sur M_PI_2, la force du comportement de poussée est dirigée vers le bas de l'écran.

L'étape suivante consiste à ajouter le comportement de gravité. Le vecteur auquel nous passons setGravityDirection se traduira par une force vers le haut de l'écran, tirant la vue d'alerte vers le haut.

UIGravityBehavior * gravityBehavior = [[UIGravityBehavior alloc] initWithItems: @ [self.alertView]]; [gravityBehavior setGravityDirection: CGVectorMake (0.0, -1.0)]; [auto.animator addBehavior: gravityBehavior];

Ce qui est intéressant à propos du comportement de collision est que nous définissons une limite qui est hors écran.

UICollisionBehavior * collisionBehavior = [[UICollisionBehavior alloc]] initWithItems: @ [self.alertView]]; [collisionBehavior addBoundaryWithIdentifier: @ "alertCollisionBoundary" dePoint: CGPointMake (self.initialAlertViewFrame.origin.x, self.initialAlertViewFrame.origin.y - 10.0) à Point: CGPointMake (self.inAlertViewFrame.origin.y). self.initialAlertViewFrame.origin.y - 10.0)]; [self.animator addBehavior: collisionBehavior];

Nous avons également besoin d'un comportement dynamique pour définir l'élasticité de la collision. Le résultat est que la vue d'alerte rebondira un peu lorsqu'elle entrera en collision avec la limite hors écran..

UIDynamicItemBehavior * itemBehavior = [[UIDynamicItemBehavior alloc]] initWithItems: @ [self.alertView]]; itemBehavior.elasticity = 0.4; [self.animator addBehavior: itemBehavior];

Nous devons également rendre la vue d’arrière-plan transparente à nouveau. Nous faisons cela en définissant la vue de fond alpha propriété à 0.0 dans un bloc d'animation.

[UIView animateWithDuration: 2.0 animations: ^ [self.backgroundView setAlpha: 0.0]; ];

Exécutez votre application une fois de plus pour voir le résultat.

6. Gestion de l'interaction utilisateur

Bien que l'affichage des alertes réponde aux interactions de l'utilisateur, nous ne savons pas pour l'instant quel bouton l'utilisateur a tapé. C'est ce sur quoi nous allons nous concentrer dans cette section.

Comme nous l'avons fait avec la composante de menu, nous allons utiliser des blocs pour résoudre ce problème. Les blocs constituent une solution élégante et peuvent souvent être plus faciles à utiliser qu'un protocole de délégué.

Nous commençons par mettre à jour le public showAlertView méthode. La méthode doit accepter un gestionnaire de complétion que la vue d'alerte appelle lorsque l'utilisateur a appuyé sur l'un des boutons. Dans AlertComponent.h, mettre à jour la déclaration du showAlertView méthode de:

- (void) showAlertView;

à:

- (void) showAlertViewWithSelectionHandler: (void (^) (NSInte buttonIndex, NSString * buttonTitle)) gestionnaire;

Le gestionnaire d'achèvement accepte deux paramètres, l'index, de type NSInteger, et le titre, de type NSString, du bouton qui a été exploité par l'utilisateur. Si nous voulons appeler le gestionnaire d'achèvement lorsque l'utilisateur appuie sur un bouton de la vue des alertes, nous devons conserver une référence au gestionnaire d'achèvement. Cela signifie que nous devons déclarer une propriété pour le gestionnaire d'achèvement. Nous faisons cela dans l'extension de classe privée dans AlertComponent.m.

@interface AlertComponent ()… @property (nonatomic, strong) void (^ selectionHandler) (NSInteger, NSString *);… @end

Toujours dedans AlertComponent.m, mettre à jour la description de la méthode comme nous l'avons fait dans le fichier d'en-tête il y a un moment et stocker le gestionnaire d'achèvement dans le selectionHandler propriété, que nous venons de déclarer.

- (void) showAlertViewWithSelectionHandler: (void (^) (NSInteger, NSString *)) gestionnaire self.selectionHandler = gestionnaire;…

La dernière pièce du puzzle appelle le gestionnaire d’achèvement dans handleButtonTap:, passer dans le tag et le titre du bouton.

- (void) handleButtonTap: (UIButton *) sender // Appelez le gestionnaire de sélection. self.selectionHandler (sender.tag, sender.titleLabel.text);…

Le composant AlertComponent est terminé. Il est temps de tout tester. Retournez à ViewController.m et mettez à jour l'action showAlertView: comme indiqué ci-dessous. Comme vous pouvez le constater, nous invoquons le nouveau showAlertViewWithSelectionHandler: méthode et passe dans un bloc, qui sera appelé quand l'utilisateur appuiera sur un bouton de l'affichage des alertes.

- (IBAction) showAlertView: (id) expéditeur [self.alertComponent showAlertViewWithSelectionHandler: ^ (NSInteger buttonIndex, NSString * buttonTitle) NSLog (@ "% ld,% @", (long) buttonIndex, buttonTitle); ];  

C'est tout. Exécutez votre application une fois de plus et inspectez la console Xcode pour voir le résultat de notre travail..

Conclusion

UIKit Dynamics a été introduit pour la première fois dans iOS 7 et peut vous aider à créer rapidement des animations réalistes. Cette courte série a montré qu’il n’était pas difficile d’utiliser la dynamique UIKit dans vos projets et que vous n’aviez pas besoin d’être un expert en mathématiques ou en physique..

Notez que UIKit Dynamics est principalement conçu pour être utilisé dans des applications basées sur des vues. Si vous recherchez une solution similaire pour les jeux, je vous recommande de jeter un coup d'œil au Sprite Kit d'Apple, qui est destiné au développement de jeux..