TIM-Magazine.swift

Attention, version Xcode 7.2 et swift 2

Contenu

TIM.Magazine.final1
 

 

Description

Avec ce tutoriel nous apprendrons à programmer une application iOS qui offre à l’utilisateur la possibilité d’habiller sa photo à partir de maquettes de magazines et de pouvoir publier le résultat sur les réseaux sociaux ‘facebook’ et ‘twitter’.
Vidéo du résultat final:
[embedyt]http://www.youtube.com/watch?v=CucHHI7697g[/embedyt]
Note: Le texte en rouge indique une tâche à réaliser en laboratoire.


Étape 1 – Réalisation de la scène principale

Action 1 – Créons un nouveau projet de type “Single View” pour le ‘iPad’.
TIM_Magazine_new_Xcode_project
Action 2 – Renseignons les information de création du projet
TIM_Magazine_new_TIM-Magazine
Action 3 – Ajoutons au projet un ‘groupe’ nommé ‘Mes ressources’.
TIM_Magazine_new_group TIM_Magazine_name_new_group


Voici les ressources du projet

TIM.Magazine.image002 TIM.Magazine.image003 TIM.Magazine.image001

Ajouter les images au projet

Action 4 – Ajoutons les trois images précédentes au projet.
Astuce:  Il faut enregistrer dans ‘download’ puis, glisser vers le projet.
Screenshot_2014-07-07_21_22_04 Screenshot_2014-07-07_21_24_54 Screenshot_2014-07-07_21_26_39 TIM_Magazine_cocher_-_copier_au_besoin TIM.Magazine.Ajouter groupe couvertures

Élaboration de la maquette de départ

Action 5 – Plaçons deux contrôles de type ‘UIButton‘ au bas de l’écran et renseignons les propriétés ‘Type‘ et ‘Image‘ pour changer leur apparence.
Elaborer la scene de depart

Définition des liens ‘MVC’ entre les boutons et le contrôleur de la scène

Action 6 – Glissons ‘ctrl+clic’ le bouton ‘facebook’ vers le le contrôleur de la scène principale.
TIM_Magazine_insert_IBAction
 
Action 7 – Renseignons les propriétés du lien  du bouton ‘facebook’
renseigner le IBAction TIM_Magazine_IBAction_code
Action 8 – Ajoutons le code suivant à la fonction ‘actionFacebook:

@IBAction func actionFacebook(sender: AnyObject) {
  println("actionFacebook")
}

Action 9 – Testons l’app dans le simulateur: emulateur01 Action 10 – Ajoutons une connexion sur le bouton ‘twitter’

//  ViewController.swift
//  TIM-Magazine.swift
import UIKit
class ViewController: UIViewController {
    /// Fonction exécutée suite à un clic du bouton 'facebook'
    @IBAction func actionFacebook(sender: AnyObject) {
        println("actionFacebook")
    } // actionFacebook
    /// Fonction exécutée suite à un clic du bouton 'twitter'
    @IBAction func actionTwitter(sender: AnyObject) {
        println("actionFacebook")
    } // actionTwitter
    /// Fonction exécutée suite au chargement de la scène en mémoire
    override func viewDidLoad() {
        super.viewDidLoad()
    } // viewDidLoad
} // ViewController


Étape 2 – Élaboration de base du premier magazine

Nous allons maintenant ajouter une scène supplémentaire à notre projet.
Action 11 – Ajoutons un nouveau groupe nommé ‘Les couvertures’ au projet.
 
groupe - couvertures
 
 
Action 12 – Dans le groupe ‘Les couvertures’, ajoutons un nouveau fichier.
Explication en classe de la notion de ‘XIB’ vs ‘StoryBoard’
nouvelle View
Action 13 – Sélectionnons un fichier de type ‘iOS – User Interface – View’
renseigner le fichier View
Action 14 – Nommons la nouvelle scène
nommer et enregistrer fichier View
 
Action 15 – Modifions le fond de la scène et ajoutons un titre.
elaboration de magazine01
Note: L’ajustement de l’alpha du fond de la scène nous permettra de voir les éléments sous la scène lorsqu’elle sera ajoutée à la scène principale.
 


Chargement d’une scène par programmation

Il nous reste maintenant à charger la scène ‘magazine01’ par programmation.
Idéalement, cette scène devrait être affichée au démarrage de l’application.
Rappelle:  La scène est une instance de la classe UIViewController.
La classe ‘UIViewController’ contient un membre de type ‘UIView’ qui permet d’afficher des éléments à l’écran.
La classe ‘UIView’ propose la méthode ‘addSubview’ pour ajouter des élements visuels à son canvas d’affichage.
Donc, pour ajouter un élément à la scène principale, il suffit d’appeler la méthode ‘addSubview(un objet visuel)’ du membre ‘view’ de l’instance de la classe de la scène.
Par exemple, pour ajouter un ‘UILabel’ à l’écran  il suffit de programmer: view.addSubView(UILabel()).
Note: « self.view » est valide aussi.
Action 16 – Ajoutons le code suivant à la méthode ‘viewDidLoad’ du contrôleur de la scène principale.

override func viewDidLoad() {
 super.viewDidLoad()
 // Début de notre code...
 // Créer la vue de 'Magazine01' par prog
 var ecranMagazine = UINib(nibName: "Magazine01", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! UIView
 // Ajouter la nouvelle ‘View’ à la scène principale
 view.addSubview(ecranMagazine);
} //viewDidLoad

Action 17 – Exécutons le projet dans le simulateur
simulateur02
Solution:  Insérer la maquette avant les boutons.
Action 18 – Observons la structure des éléments de la scène
 
inserer magazine avant les boutons
 
Action 19 – Modifions le code, pour ajouter le magazine avant les boutons ‘facebook’ et ‘twitter’

// Insérer la nouvelle ‘View’ avant les boutons fb et twitter
println("view.subviews.count: \(view.subviews.count)")
view.insertSubview(ecranMagazine, atIndex: (view.subviews.count - 2) - 1 )
// Ou bien ceci pour ajouter au haut de la liste
view.insertSubview(ecranMagazine, atIndex: 0)

Action 20 – Exécutons le projet dans le simulateur
simulateur03

Regroupement des éléments d’interaction

L’approche précédente pose un problème, il faudra modifier l’indice d’insertion à chaque fois que nous ajouterons des éléments de contrôle à la scène principale.
Par exemple, un menu pour changer de magazine.
Il est possible de regrouper des objets visuels ensemble grâce à l’objet ‘UIView’.
Action 21 – Ajoutons un objet ‘UIView’ à la scène principale.
ajouter viewMenu
Action 22 – Remplaçons la valeur de  paramètre ‘atIndex’ pour ‘view.subviews.count – 1″
simulateur avec menu
 
 

Quelques petits ajustements

Action 23 – Renseignons le fond de la scène principale à « noir » et le fond de la maquette ‘Magazine01′ à « Clear color’ (transparent).
scene fond a noir fond magazine01
Action 24 – Testons avec le simulateur:
etape01
 
Réflexion:  Nous assumons que la ‘view’ du fichier XIB sera toujours à la position [0] du XIB.  Si Apple change la position de la ‘view’, notre programme ne fonctionnera plus correctemnt.
La méthode recommandée par Apple pour charger la ‘view’ du fichier XIB est la suivante:

var ecranMagazine = UIView()
// Parcourir tous les éléments du fichier
for x in UINib(nibName: "magazine01", bundle: nil).instantiateWithOwner(nil, options: nil) {
  // si objet courant de type 'UIView' alors renseigner notre variable
  if x.isKindOfClass(UIView) {
    ecranMagazine = x as! UIView
  } // if
} // for

 
Téléchargement du projet à cette étape.


Étape 03 – Design des maquettes

Action 25 – Vous devez réaliser les maquettes suivantes:
Note:  Pendant l’étape d’élaboration des maquettes, il est recommandé de fixer la couleur de la scène à noir.  Cela va permettre de distinguer le texte blanc. Nous changerons le fond de ‘noir’ à ‘transparent : clearcolor’ à l’étape de chargement des interfaces.
Astuce: Pensez à copier/coller le fichier Magazine01.xib vers 02..04.xib.

Magazine 01

magazine01

Magazine 02

magazine02

Magazine 03

 

magazine03

Magazine 04 (votre design perso)

magazine04

Les ressources
TIM.Magazine.image012 TIM.Magazine.image011Rolling_Stone_logo
 


Étape 04 – Tourner les pages avec un menu

 
Action 26 – Ajoutons un ‘UISegmentedControl’ dans la section interactive.
TIM.Magazine.segmented.control
TIM.Magazine.titre.segments
 
Résultat final:
TIM.Magazine.segmented.control.final
 
Définissons un lien IBAction sur le  ‘UISegmentedControl’
TIM.Magazine.segmented.control.IBAction
 

Plaçons une trace dans la méthode ‘actionTournerPages’ pour confirmer qu’il y a effectivement appel suite à une sélection.
/// Fonction exécutée suite à une sélection dans le 'UISegmentedControl'.  Note: Doit-être liée au UISC.
@IBAction func actionTournerPages(sender: AnyObject) {
  let selection = (sender as! UISegmentedControl).selectedSegmentIndex
  println("actionTournerPages: la sélection vaut: \(selection)")
}

TIM.Magazine.segmented.control.selection
 

De façon empirique, nous constatons que l’objet ‘UISegmentedControl’ retourne une valeur entre 0 et nbÉléments-1.
Il ne reste plus qu’à programmer une structure logique qui insérera la couverture magazine correspondant à la sélection de l’utilisateur.
Note :
Pour enlever un objet de la scène il faut utiliser la syntaxe suivante :
ecranMagazine.removeFromSuperview()
Note: Il est important de déclarer la variable ‘ecranMagazine‘ comme propriété de la classe de la scène.
class ViewController: UIViewController {
var ecranMagazine =  UIView()

func chargerMagazine(no:Int) {
var nomMagazine = …
  ecranMagazine = UINib(nibName: nomMagazine, bundle: nil).instantiateWithOwner(nil, options: nil)[0] as  UIView
  } // chargerMagazine
} //  ViewController

À faire par l’étudiant en laboratoire
Programmer le chargement de la maquette de magazine correspondant au choix de l’utilisateur.
Il est important de normaliser le code. Pas de structures lourdes dans votre code. Ne pas utiliser l’instruction ‘if’ ou ‘switch’.
Il est possible de réaliser la tâche avec un maximum de 4 lignes de code : 
@IBAction func actionTournerPages(sender: AnyObject) {
// 1 - Retirer le magazine courant de la scène
// 2 - Construire une chaine de caractères qui décrit le nom du fichier: 'Magazine0' + selectionCourante + 1
// 3 - Charger le magazine à partir d’un nom d’un fichier NIB
// 4 - Ajouter le magazine à la scène principale
}

Résultat:
TIM.Magazine.final1  TIM.Magazine.final2  TIM.Magazine.final3  TIM.Magazine.final4
 


Étape 5 – Intégration des réseaux sociaux

PRÉ-REQUIS – Configuration des comptes sociaux sur l’appareil iOS.
Note: Au moment d’écrire cet exercice, le social.FrameWork n’était pas encore disponible dans la librairie iOS version 8.  Assurez-vous de renseigner le version 7.x dans le paramètre de déploiement du projet.
TIM_Magazine_08
TIM_Magazine_07
Capture d’une Vue vers un objet UIImage

    func sauvegarderEcran(){
        // Description : méthode servant à capturer l’écran et au besoin,
        // en faire une sauvegarde dans l’album photos.
        // 1 - Préparer un contexte de dessin à partir de la taille de la scène
        UIGraphicsBeginImageContext(self.view.bounds.size);
        // 2 – Dessiner à partir du claque par défaut de la scène
        self.view.layer.renderInContext(UIGraphicsGetCurrentContext());
        // 3 – Stocker le résultat dans notre objet local
        imageFinale = UIGraphicsGetImageFromCurrentImageContext();
        // 5 – Fermer le contexte de dessin
        UIGraphicsEndImageContext();
        // 6 – Facultatif - Stocker une copie de la capture d’écran dans l’album photos
        UIImageWriteToSavedPhotosAlbum(imageFinale, nil, nil, nil );
    } // sauvegarderEcran

 
Vérifions la présence de la capture dans l’album de photos.
 
Envoyer un ‘post’ vers Facebook
 

import Social
func posterSurFacebook() {
  // Les étapes pour utiliser ‘facebook’
  // 1 - Tester si le service et les informations de connexion sont dispo
  if SLComposeViewController.isAvailableForServiceType(SLServiceTypeFacebook)
  {
    // 2 - Créer un feuille pour le 'post'
    let controleur = SLComposeViewController (forServiceType: SLServiceTypeFacebook)
    // 3 - Composer le message
    controleur.setInitialText("Test avec Swift et Xcode");
    // 4 - Ajouter une image - facultatif
    controleur.addImage(imageFinale);
    // 5 - Ajouter un lien - facultatif
    controleur.addURL(NSURL(fileURLWithPath:"/cours/xcode/"));
    // 6 - Présenter la fenêtre de confirmation à l'utilisateur
    self.presentViewController(controleur, animated: true, completion: nil);
    } // if Facebook
} // posterSurFacebook

 
Modifions la méthode ‘actionFacebook’.

    @IBAction func actionFacebook(sender: AnyObject) {
        println("actionFacebook")
        sauvegarderEcran()
        posterSurFacebook()
    } // actionFacebook

Action – Testons l’application
 
Action – Modifiez le méthode actionTwitter
 
Il reste à cacher la zone menu avant de capturer l’écran.
Définissons un IBOutlet sur la View du menu.
TIM_Magazine_06
Ajoutons le code suivant à la méthode capturerEcran.

    func sauvegarderEcran(){
       // Cacher le menu
        leMenu.hidden = true
        // 1  ...
        // 6
        leMenu.hidden = false
     } // sauvegarderEcran

 


 
 

Étape 6 – Utilisation d’un UIScrollView

Note: Cette étape est facultative.  Il n’y aura pas d’explication en classe, Si vous la réalisez, la correction du projet se fera sur 12/10.
Le contrôle ‘UIScrollView’ permet d’afficher un contenu plus grand que sa zone d’affichage.
Une gestuelle sur l’écran donne accès au contenu non visible.
Méthode d’utilisation du contrôle:
1 – Placer le ‘UIScrollView’ sur une scène,
2 – Par programmation, ajouter des objets dans le ‘UIScrollView’ en renseignant correctement les positions x/y,
3 – Renseigner  la propriété  ‘UIScrollView’.contentSize
 

    func chargerLesMagazines() {
        // Renseigner la largeur de la zone de contenu du scrollView en fn du nb de pages.
        let pagesScrollViewSize = zoneAffichageDesElements.frame.size
        zoneAffichageDesElements.contentSize = CGSizeMake(pagesScrollViewSize.width * Float(nbMagazines), pagesScrollViewSize.height)
        for page in 0..<nbMagazines {
            // Placer les Views un à la suite de l'autre sur le plan des 'x'
            var frame:CGRect = zoneAffichageDesElements.bounds
            frame.origin.x = frame.size.width * Float(page)  // la première page (0) sera à x = 0
            frame.origin.y = 0
            // Charger le 'xib' courant
            var nomNIB = "Magazine0\(page+1)"
            println(nomNIB)
            if var newPageView = UINib(nibName: nomNIB, bundle: nil).instantiateWithOwner(nil, options: nil)[0] as? UIView {
                newPageView.frame = frame;
                // Ajouter au scrollView
                zoneAffichageDesElements.addSubview(newPageView)
            }  // if newPageView
        } // for page
    } // chargerLesMagazines()

 
Testons
Activons le ‘paging enable’
Ajoutons un UIPageControl (indicateur de la page courante/nbPages)
Expliquer Délégation

   // Une des Méthodes de délégation de UIScrollView
    func scrollViewDidEndDecelerating(scrollView: UIScrollView){
        println("scrollViewDidEndDecelerating")
        let positionPage = Int(zoneAffichageDesElements.contentOffset.x / zoneAffichageDesElements.frame.size.width)
        indicateurDePages.currentPage = positionPage
    }  // scrollViewDidEndDecelerating

 
Remplaçons  le code de la méthode ‘viewDidLoad.

    override func viewDidLoad() {
        super.viewDidLoad()
        // Début de notre code...
        // L'ancien code de chargement du magazine01 doit-être supprimé.
        chargerLesMagazines()
    }  // viewDidLoad

 
FIN  du laboratoire


Document rédigé par Alain Boudreault – Juillet 2014 – Révision:  août 2015 pour swift 1.2