iOS 8 Création d'un widget aujourd'hui

L'une des nouvelles fonctionnalités les plus populaires introduites dans iOS 8 est la possibilité de créer plusieurs types d'extensions. Dans ce didacticiel, je vais vous guider dans le processus de création d’un widget personnalisé pour le Aujourd'hui section du centre de notification. Mais d’abord, passons brièvement en revue quelques sujets sur les extensions et comprenons les concepts importants qui sous-tendent les widgets.

1. Qu'est-ce qu'une extension??

Une extension est un binaire à usage spécifique. Ce n'est pas une application complète, il faut un contenant l'application être distribué. Cela pourrait être votre application existante, qui peut inclure une ou plusieurs extensions, ou une nouvelle créée. Bien que l'extension ne soit pas distribuée séparément, elle possède son propre conteneur.

Une extension est lancée et contrôlée via son application hôte. Cela peut être Safari, par exemple, si vous créez une extension de partage, ou l'application système Today qui prend en charge le centre de notification et d'autres widgets. Chaque zone de système prenant en charge l’extension est appelée un point d'extension.

Pour créer une extension, vous devez ajouter une cible au projet de l'application contenant. Les modèles fournis par Xcode incluent déjà les infrastructures appropriées pour chaque point d'extension, ce qui permet à l'application d'interagir avec et de suivre les stratégies correctes de l'application hôte..

2. Point d'extension aujourd'hui

Les extensions créées pour le point d'extension Today, appelées widgets, sont conçues pour fournir un accès simple et rapide aux informations. Les widgets sont liés au framework Notification Center. Il est important de concevoir votre widget avec une interface utilisateur simple et ciblée, car trop d'interaction peut être un problème. Notez également que vous n'avez pas accès à un clavier.

Les widgets doivent bien fonctionner et garder leur contenu à jour. La performance est un gros point à considérer. Votre widget doit être prêt rapidement et utiliser les ressources à bon escient. Cela évitera de ralentir toute l'expérience. Le système termine les widgets qui utilisent trop de mémoire, par exemple. Les widgets doivent être simples et ciblés sur le contenu qu'ils affichent..

C'est assez de théorie pour l'instant. Commençons par créer un widget personnalisé aujourd'hui. Le widget que nous sommes sur le point de créer affichera des informations sur l'utilisation du disque, y compris une barre de progression pour fournir une référence visuelle rapide à l'utilisateur. En cours de route, nous aborderons également d’autres concepts importants des extensions iOS 8..

3. Configuration cible

Étape 1: Configuration du projet

Si vous souhaitez créer ce widget en tant qu'extension d'une application existante, ouvrez votre projet Xcode et passez à la deuxième étape. Si vous partez de zéro comme moi, vous devez d'abord créer une application contenant.

Ouvrez Xcode et dans le Fichier sélection du menu Nouveau> Projet… . Nous utiliserons Objective-C comme langage de programmation et le Application à vue unique modèle pour commencer.

Étape 2: Ajouter une nouvelle cible

Ouvrez le Fichier menu et choisir Nouveau> Cible… . dans le Extension de l'application catégorie, sélectionnez la Extension aujourd'hui modèle.

Vous remarquerez que le Projet à laquelle la cible sera ajoutée est le projet avec lequel nous travaillons actuellement et l'extension sera intégrée à l'application qui la contient. Notez également que l'extension a un identifiant de paquet distinct basé sur celui de l'application contenante., com.tutsplus.Today.Used-Space.

Cliquez sur Suivant, donnez un nom à votre widget, par exemple, Espace utilisé, et cliquez terminer pour créer la nouvelle cible. Xcode a créé un nouveau schéma pour vous et il vous demandera de l'activer pour vous. Cliquez sur Activer continuer.

Xcode a créé un nouveau groupe pour le widget nommé Espace utilisé et ajouté un certain nombre de fichiers, un UIViewController sous-classe et un storyboard. C'est vrai, un widget n'est rien de plus qu'un contrôleur de vue et un storyboard. Si vous ouvrez l'en-tête du contrôleur de vue dans l'éditeur de code, vous remarquerez qu'il s'agit bien d'un sous-classement. UIViewController.

Si vous sélectionnez la cible d'extension dans la liste des cibles, ouvrez le Phases de construction onglet, et développez le Lien binaire avec des bibliothèques section, vous verrez que la nouvelle cible est liée à la Centre de notification cadre.

4. Interface utilisateur

Nous allons maintenant construire une interface utilisateur de base pour notre widget. Déterminer la taille du widget est important et il existe deux façons de dire au système la quantité d'espace dont nous avons besoin. L’un utilise la mise en page automatique et l’autre utilise le PreferredContentSize propriété du contrôleur de vue.

Le concept de disposition adaptative est également applicable aux widgets. Nous avons non seulement des iPhones de différentes largeurs (et des iPad et futurs appareils), mais nous nous rappelons également que le widget peut avoir besoin d'afficher son contenu en orientation paysage. Si l'interface utilisateur peut être décrite avec des contraintes de mise en page automatique, il s'agit d'un avantage évident pour le développeur. La hauteur peut être ajustée plus tard avec setPreferredContentSize: si besoin.

Étape 1: Ajout d'éléments

Ouvrir MainInterface.storyboard dans l'éditeur Xcode. Vous remarquerez qu'une étiquette affichant "Hello World" est déjà présente dans la vue du contrôleur de vue. Sélectionnez-le et supprimez-le de la vue, car nous ne l'utilisons pas. Ajoutez une nouvelle étiquette à la vue et alignez-la sur la marge droite, comme indiqué ci-dessous..

dans le Inspecteur d'attributs, définissez la couleur du texte sur blanc, l'alignement du texte sur la droite et le texte de l'étiquette sur 50,0%.

Sélectionner Taille adaptée au contenu de Xcode Éditeur menu pour redimensionner correctement l'étiquette si elle est trop petite pour s'adapter à son contenu.

Ensuite, ajoutez un UIProgressView exemple à gauche de l'étiquette et positionnez-la comme indiqué ci-dessous.

Avec la vue de progression sélectionnée, modifiez le Teinte de progrès attribuer dans le Inspecteur d'attributs au blanc et au Piste teinte couleur gris foncé. Cela le rendra plus visible. Cela semble bon jusqu'à présent. Il est temps d'appliquer certaines contraintes.

Étape 2: Ajout de contraintes

Sélectionnez l’étiquette de pourcentage et ajoutez une contrainte de haut, de bas et de fin, comme indiqué ci-dessous. Assurez-vous de décocher la case Limiter aux marges case à cocher.

Sélectionnez la vue de progression et ajoutez une contrainte de début, de fin et de fin. Utilisez cette opportunité pour changer l’espace principal en 3 et n'oubliez pas de décocher Limiter aux marges.

Étant donné que nous avons modifié la valeur de la contrainte principale de la vue de progression, nous avons un petit problème à résoudre. Le cadre de la vue de progression ne reflète pas les contraintes de la vue de progression. La vue de progression sélectionnée, cliquez sur le bouton Résoudre les problèmes de mise en page automatique bouton en bas et choisissez Mettre à jour les cadres du Vues sélectionnées section. Ceci mettra à jour le cadre de la vue de progression en fonction des contraintes définies précédemment.

Étape 3: Construire et exécuter

Il est temps de voir le widget en action. Avec le Espace utilisé schéma sélectionné, sélectionnez Courir du Produit menu ou hit Commande-R. Révélez le centre de notification en faisant glisser votre doigt du haut vers le bas et appuyez sur le bouton modifier bouton en bas du centre de notification. Votre widget doit être disponible pour être ajouté à la section Aujourd'hui. Ajoutez-le à la section Aujourd'hui en appuyant sur le bouton Ajouter à sa gauche.

Voici à quoi devrait ressembler notre extension.

Cela a l'air bien, mais pourquoi y a-t-il autant d'espace sous la vue et l'étiquette de progression? Aussi, pourquoi le système d'exploitation n'a-t-il pas respecté la principale contrainte de la vue de progression??

Les deux problèmes sont des marges standard définies par le système d'exploitation. Nous allons changer cela dans la prochaine étape. Notez cependant que la marge de gauche est souhaitable car elle aligne la vue de progression avec le nom du widget..

Si vous faites pivoter votre appareil ou exécutez l'application sur un autre appareil, vous remarquerez que le widget l'ajuste correctement. C'est grâce à la mise en page automatique.

Étape 4: Fixer la marge inférieure

Ouvrir TodayViewController.m dans l'éditeur de Xcode. Vous remarquerez que le contrôleur de vue est conforme à la NCWidgetProviding protocole. Cela signifie que nous devons mettre en œuvre le widgetMarginInsetsForProposedMarginInsets: méthode et retourner une marge personnalisée en retournant un UIEdgeInsets structure. Mettez à jour l'implémentation de la méthode comme indiqué ci-dessous.

- (UIEdgeInsets) widgetMarginInsetsForProposedMarginInsets: (UIEdgeInsets) margins margins.bottom = 10.0; retourner les marges; 

Exécutez à nouveau l'application pour voir le résultat. Le widget devrait être plus petit avec moins de marge en bas. Vous pouvez personnaliser ces marges pour obtenir le résultat recherché.

Étape 5: Connexion des prises

Avant de poursuivre, finissons l’interface utilisateur en ajoutant deux prises. Une fois le fichier de storyboard ouvert, passez à l’éditeur assistant et assurez-vous qu’il affiche TodayViewController.m.

Tenir Contrôle et faites glisser de l'étiquette vers l'interface du contrôleur de vue pour créer un point de vente pour l'étiquette. Nommez le point de vente percentLabel. Répétez cette étape et créez un point de vente nommé barView pour le UIProgressView exemple.

5. Affichage de données réelles

Nous allons utiliser le NSFileManager classe pour calculer l'espace disponible de l'appareil. Mais comment mettre à jour le widget avec ces données?

C’est là une autre méthode de la NCWidgetProviding le protocole entre en jeu. Le système d'exploitation appelle le widgetPerformUpdateWithCompletionHandler: méthode lorsque le widget est chargé et qu'il peut également être appelé en arrière-plan. Dans ce dernier cas, même si le widget n'est pas visible, le système peut le lancer et demander des mises à jour pour enregistrer un instantané. Cet instantané sera affiché lors de la prochaine apparition du widget, généralement pendant une courte période jusqu'à ce que le widget soit affiché..

L'argument transmis dans cette méthode est un gestionnaire d'achèvement qui doit être appelé lorsque le contenu ou les données sont mis à jour. Le bloc prend un paramètre de type NCUpdateResult décrire si nous avons un nouveau contenu à afficher. Sinon, le système d'exploitation saura qu'il n'est pas nécessaire de sauvegarder un nouvel instantané..

Étape 1: Propriétés

Nous devons d’abord créer des propriétés pour contenir les tailles libre, utilisée et totale. Nous allons également ajouter une propriété pour contenir l'espace utilisé sur le périphérique. Cela nous permet une plus grande flexibilité plus tard. Ajoutez ces propriétés à l'extension de classe dans TodayViewController.m.

@property (nonatomic, assign) unsigned long long fileSystemSize; @property (nonatomic, assign) unsigned long long freeSize; @property (nonatomic, assign) unsigned long long usedSize; @property (nonatomic, assign) double usedRate;

Étape 2: mise en œuvre updateSizes

Ensuite, créez et implémentez une méthode d'assistance, updateSizes, pour récupérer les données nécessaires et calculer l'espace utilisé par l'appareil.

- (void) updateSizes // Récupère les attributs de NSFileManager NSDictionary * dict = [[NSFileManager defaultManager] attributsOfFileSystemForPath: erreur NSHomeDirectory (): nil]; // Définit les valeurs self.fileSystemSize = [[dict valeurForKey: NSFileSystemSize] unsignedLongLongValue]; self.freeSize = [[dict valueForKey: NSFileSystemFreeSize] unsignedLongLongValue]; self.usedSize = self.fileSystemSize - self.freeSize; 

Étape 3: mise en cache

Nous pouvons profiter de NSUserDefaults pour enregistrer l'espace utilisé calculé entre les lancements. Le cycle de vie d'un widget est court. Par conséquent, si nous mettons en cache cette valeur, nous pouvons configurer l'interface utilisateur avec une valeur initiale, puis calculer la valeur réelle..

Cela est également utile pour déterminer si nous devons ou non mettre à jour l’instantané du widget. Créons deux méthodes pratiques pour accéder à la base de données par défaut des utilisateurs.

// @implementation - (double) usedRate return [[[NSUserDefaults standardUserDefaults]] valueForKey: RATE_KEY] doubleValue];  - (void) setUsedRate: (double) usedRate NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; [defaults setValue: [NSNumber numberWithDouble: usedRate] forKey: RATE_KEY]; [synchroniser par défaut]; 

Notez que nous utilisons une macro RATE_KEY alors n'oubliez pas d'ajouter celui-ci en haut de TodayViewController.m.

// Macro pour la clé NSUserDefaults #define RATE_KEY @ "kUDRateUsed"

Étape 4: Mise à jour de l'interface utilisateur

Parce que notre widget est un contrôleur de vue, le viewDidLoad La méthode est un bon endroit pour mettre à jour l'interface utilisateur. Nous utilisons une méthode d'assistance, updateInterface faire cela.

- (void) updateInterface double rate = self.usedRate; // récupère la valeur mise en cache self.percentLabel.text = [NSString stringWithFormat: @ "%. 1f %%", (rate * 100)]; self.barView.progress = rate;  - (void) viewDidLoad [super viewDidLoad]; [auto updateInterface]; 

Étape 5: invocation du gestionnaire d'achèvement

Le nombre d'octets libres a tendance à changer assez souvent. Pour vérifier si nous devons réellement mettre à jour le widget, nous vérifions l'espace utilisé calculé et appliquons un seuil de 0,01% au lieu du nombre exact d'octets libres. Changer la mise en œuvre widgetPerformUpdateWithCompletionHandler: comme indiqué ci-dessous.

- (void) widgetPerformUpdateWithCompletionHandler: (void (^) (NCUpdateResult)) completionHandler [self updateSizes]; double newRate = (double) self.usedSize / (double) self.fileSystemSize; if (newRate - self.usedRate < 0.0001)  completionHandler(NCUpdateResultNoData);  else  [self setUsedRate:newRate]; [self updateInterface]; completionHandler(NCUpdateResultNewData);  

Nous recalculons l'espace utilisé et, s'il est significativement différent de la valeur précédente, sauvegardons la valeur et mettons à jour l'interface. Nous disons ensuite au système d'exploitation que quelque chose a changé. Si ce n'est pas le cas, un nouvel instantané n'est pas nécessaire. Bien que nous ne l'utilisions pas dans cet exemple, il existe aussi un NCUpdateResultFailed valeur pour indiquer qu'une erreur s'est produite.

Étape 6: Construire et exécuter

Exécutez votre application une fois de plus. Il devrait maintenant afficher la valeur correcte de la quantité d’espace utilisé par votre appareil..

6. Récapitulation

Passons en revue le cycle de vie de votre nouveau widget. Lorsque vous ouvrez le Aujourd'hui Dans le panneau de configuration, le système peut afficher un instantané précédent jusqu’à ce qu’il soit prêt. La vue est chargée et votre widget récupère une valeur mise en cache dans NSUserDefaults et l'utiliser pour mettre à jour l'interface utilisateur.

Suivant, widgetPerformUpdateWithCompletionHandler: est appelé et il recalculera la valeur réelle. Si la valeur en cache et la nouvelle valeur ne sont pas significativement différentes, nous ne faisons rien. Si la nouvelle valeur est sensiblement différente, nous la mettons en cache et mettons à jour l'interface utilisateur en conséquence..

En arrière-plan, le widget peut être lancé par le système d'exploitation et le même processus est répété. Si NCUpdateResultNewData est renvoyé, un nouvel instantané est créé pour être affiché lors de la prochaine apparition.

7. Ajout de plus d'informations et d'animation

Bien que nous montrions déjà l’espace utilisé, il serait intéressant d’avoir un nombre précis. Pour éviter d'encombrer l'interface utilisateur, nous allons rendre notre widget plus interactif. Si l'utilisateur appuie sur l'étiquette de pourcentage, le widget se développe et affiche une nouvelle étiquette avec des nombres absolus. C'est aussi une excellente occasion d'apprendre à utiliser l'animation dans des widgets..

Étape 1: modification de l'interface utilisateur

Ouvrir MainInterface.storyboard et sélectionnez l'étiquette de pourcentage. dans le Inspecteur d'attributs, sous le Vue section, trouver le Interaction utilisateur activée option et l'activer.

Ensuite, nous devons supprimer la contrainte inférieure de l’étiquette. La distance entre l'étiquette et le bas de la vue changera par programme, ce qui signifie que la contrainte deviendrait invalide..

Sélectionnez l'étiquette, ouvrez le Taille zone dans le Inspecteur de taille, sélectionnez la contrainte d'espace en bas et appuyez sur supprimer. Vous pouvez également sélectionner manuellement le guide de contraintes dans la vue et le supprimer. L'étiquette a maintenant seulement une contrainte d'espace haut et bas comme indiqué ci-dessous.

Sélectionnez le contrôleur de vue en cliquant sur la première des trois icônes en haut de la scène. dans le Taille zone de la Inspecteur de taille, régler la hauteur à 106.

Ajoutez une nouvelle étiquette à la vue et, comme nous l’avons déjà fait, définissez sa couleur sur blanc dans le champ. Inspecteur d'attributs. De plus, définissez le nombre de lignes sur 3, la hauteur à 61, et la largeur 200. Cela devrait suffire à trois lignes d’information. Vous voulez aussi qu'il soit aligné sur les marges inférieure et gauche.

La dernière étape consiste à ouvrir l’assistant éditeur et à créer un débouché pour l’étiquette nommée détailsLabel.

Étape 2: Configuration

Le widget ne sera développé que pendant un bref instant. Nous pourrions sauver un booléen dans NSUserDefaults et chargez-le en vous souvenant de l'état précédent, mais, pour rester simple, chaque fois que le widget est chargé, il sera fermé. Lorsque vous appuyez sur l’étiquette de pourcentage, les informations supplémentaires apparaissent..

Définissons d’abord deux macros en haut de TodayViewController.m pour aider avec les tailles.

#define kWClosedHeight 37.0 #define kWExpandedHeight 106.0

Dans viewDidLoad, ajoutez deux lignes de code pour définir la hauteur initiale du widget et pour rendre l’étiquette de détails transparente. Nous allons fondre dans l'étiquette de détails lorsque l'étiquette de pourcentage est exploitée.

- (void) viewDidLoad [super viewDidLoad]; [auto updateInterface]; // new [self setPreferredContentSize: CGSizeMake (0.0, kWClosedHeight)]; [self.detailsLabel setAlpha: 0.0]; 

Notez que nous définissons la largeur du widget sur 0.0, parce que la largeur sera définie par le système d'exploitation.

Étape 3: Mise à jour de l'étiquette de détails

Dans l’étiquette de détail, nous montrons les valeurs d’espace libre, utilisé et total disponible à l’aide de NSByteCountFormatter. Ajouter l'implémentation suivante au contrôleur de vue.

-(void) updateDetailsLabel NSByteCountFormatter * formatter = [[NSByteCountFormatter alloc]] init]; [formateur setCountStyle: NSByteCountFormatterCountStyleFile]; self.detailsLabel.text = [NSString stringWithFormat: @ "Utilisé: \ t% @ \ nFree: \ t% @ \ nTotal: \ t% @", [formateur stringFromByteCount: self.usedSize], [formatter stringFromByteCount: self.freeSize. ], [formateur stringFromByteCount: self.fileSystemSize]]; 

Étape 4: Capturer les touches

Pour détecter les contacts, nous substituons la touchesBegan: withEvent: méthode. L'idée est simple, chaque fois qu'une touche est détectée, le widget est développé et l'étiquette de détails est mise à jour. Notez que la taille du widget est mise à jour en appelant setPreferredContentSize: sur le contrôleur de vue.

-(void) touchesBegan: (NSSet *) touche withEvent: (UIEvent *) event [self updateDetailsLabel]; [self setPreferredContentSize: CGSizeMake (0.0, kWExpandedHeight)]; 

Étape 5: Ajout d'animation

Même si le widget fonctionne correctement, nous pouvons améliorer l'expérience utilisateur en fondant l'étiquette de détails pendant que le widget se développe. Ceci est possible si nous mettons en œuvre viewWillTransitionToSize: withTransitionCoordinator:. Cette méthode est appelée lorsque la hauteur du widget change. Puisqu’un objet de coordination de transition est passé, nous pouvons inclure des animations supplémentaires.

Comme vous pouvez le constater, nous modifions la valeur alpha de l'étiquette de détails, mais vous pouvez ajouter tout type d'animation qui, à votre avis, améliore l'expérience utilisateur..

-(void) viewWillTransitionToSize: (CGSize) taille withTransitionCoordinator: (id) coordinator [coordinator animateAlongsideTransition: ^ (id contexte) [self.detailsLabel setAlpha: 1.0];  complétion: nil]; 

Étape 6: Construire et exécuter

Nous sommes prêts à exécuter l'application une fois de plus. Essayez-le et appuyez sur l'étiquette de pourcentage pour révéler les nouveaux détails.

Conclusion

Bien que toute cette logique puisse sembler excessivement complexe pour une tâche aussi simple, vous allez maintenant être familiarisé avec le processus complet de création d'une extension Today. Gardez ces principes à l'esprit lors de la conception et de la construction de votre widget. N'oubliez pas de rester simple et direct, et n'oubliez pas les performances.

La mise en cache ici ne serait pas du tout nécessaire avec ces opérations rapides, mais il est particulièrement important si le traitement est coûteux. Utilisez vos connaissances des contrôleurs de vue et vérifiez que cela fonctionne pour différentes tailles d'écran. Il est également recommandé d'éviter les vues de défilement ou la reconnaissance tactile complexe..

Bien que l'extension ait un conteneur séparé, comme nous l'avons vu précédemment, il est possible d'activer le partage de données entre l'extension et l'application qui la contient. Vous pouvez aussi utiliser NSExtensionContextde openURL: completionHandler: avec un schéma d'URL personnalisé pour lancer votre application à partir du widget. Et si le code est ce que vous devez partager avec votre extension, continuez et créez un cadre à utiliser dans votre application et votre extension..

J'espère que les connaissances présentées ici vous seront utiles lors de la construction de votre prochain excellent widget d'aujourd'hui..