Una delle modifiche introdotte con iOS 6 è la possibilità di utilizzare UIPageViewController per utilizzare un'animazione a scorrimento anziché lo stile di rotazione delle pagine standard. Continua a leggere per sapere come possiamo usarlo per creare facilmente un effetto di visualizzazione a scorrimento impaginato!
Per esplorare queste modifiche creeremo un'applicazione "immagine rater" in cui gli utenti possono scorrere le diverse immagini e assegnare una valutazione a ciascuna di esse. Sebbene la premessa sia di base, ti darà una buona possibilità di iniziare a utilizzare UIPageControl con il nuovo stile.
Prima di iniziare, avremo bisogno di alcune immagini. Salta su Wikipedia e scarica 5 diverse immagini che sono concesse in licenza in base a un creativo comune. Crea un nuovo progetto Xcode con un modello vuoto. Chiamalo "ImageRater" o qualcosa di equivalente. Assicurati inoltre che il dispositivo di destinazione sia impostato su iPad, la storybording sia disattivata e ARC sia attivo.
Questo progetto sarà progettato per essere utilizzato solo in orientamento orizzontale. Prima di iniziare, apri le impostazioni del progetto e seleziona solo gli orientamenti del paesaggio.
Successivamente, dobbiamo creare l'oggetto modello e visualizzare il controller responsabile della visualizzazione dell'immagine. Crea una nuova classe chiamata "ImageModel" che eredita da NSObject. Questa sarà una semplice classe del modello che contiene una stringa che rappresenta il nome del file immagine e un intero che rappresenta il "rating" dell'immagine:
ImageModel.h
@interface ImageModel: NSObject - (id) initWithImageName: (NSString *) imageName; @property (nonatomic, strong) NSString * imageName; @property (nonatomic) NSInteger rating; @fine
Abbiamo anche creato un metodo init personalizzato che renderà più semplice la creazione di questi con un nome immagine. Nell'implementazione di file m, il metodo init in questo modo:
ImageModel.m
@implementation ImageModel - (id) initWithImageName: (NSString *) imageName self = [super init]; if (self) _imageName = imageName; _rating = 0; return self;
Anche il controller della vista che visualizzerà l'immagine sarà molto semplice. Crea una nuova classe chiamata ImageViewController (ereditando UIViewController) e assegnagli le seguenti proprietà (oltre all'importazione di ImageModel.h):
ImageViewController.h
#import "ImageModel.h" @interface ImageViewController: UIViewController @property (nonatomic, strong) UIImageView * imageView; @property (nonatomic, strong) etichetta UILabel *; @property (nonatomic, strong) Modello ImageModel *; @fine
E nel file .m, aggiungi il seguente codice:
ImageViewController.m
- (void) viewDidLoad [super viewDidLoad]; [self.view setBackgroundColor: [UIColor whiteColor]]; CGRect insetFrame = CGRectMake (20, 80, self.view.frame.size.width - 40, self.view.frame.size.height - 100); _imageView = [[UIImageView alloc] initWithFrame: insetFrame]; _imageView.backgroundColor = [UIColor clearColor]; [_imageView setAutoresizingMask: UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; [_imageView setImage: [UIImage imageNamed: _model.imageName]]; [[visualizzazione automatica] addSubview: _imageView];
Al caricamento della vista, imposteremo il colore di sfondo delle viste e imposteremo imageView.
Crea una nuova classe chiamata "RootViewController" (che eredita da UIViewController). Questo sarà dove l'azione accade. Conterrà PageViewController, l'etichetta che mostra il nome e la classifica dell'immagine, così come uno stepper che consente all'utente di impostare la valutazione per l'immagine.
Una volta creata la classe, apri il file di intestazione delegati dell'app, importa la classe RootViewController e impostala come una proprietà:
AppDelegate.h
#import "RootViewController.h" @interface AppDelegate: UIResponder@property (strong, nonatomic) finestra UIWindow *; @property (strong, nonatomic) RootViewController * viewController; @fine
E nel file di implementazione impostalo come il controller della vista radice:
AppDelegate.m
- Applicazione (BOOL): l'applicazione (UIApplication *) ha fattoFinishLaunchingWithOptions: (NSDictionary *) launchOptions self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bound]]; // Override point per la personalizzazione dopo l'avvio dell'applicazione. self.viewController = [[RootViewController alloc] init]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES;
Aprire il file .h di RootViewController e assegnargli le seguenti proprietà e renderlo conforme ai metodi UIPageViewControllerDataSource e Delegate:
RootViewController.h
@interface RootViewController: UIViewController@property (nonatomic, strong) UIPageViewController * pageViewController; @property (nonatomic, strong) NSMutableArray * modelArray; @property (nonatomic) NSInteger vcIndex; @property (nonatomic, strong) UIStepper * rateStepper; @property (nonatomic, strong) UILabel * imageLabel; - (void) stepperValueChanged: (id) mittente; @fine
La paginaViewController sarà responsabile della visualizzazione di ImageViewControllers e l'array del modello sarà responsabile della memorizzazione degli oggetti imageModel. VcIndex sarà responsabile di tenere traccia dell'indice della pagina corrente. RateStepper consentirà all'utente di valutare un'immagine in alto o in basso. ImageLabel mostrerà il nome e la valutazione dell'immagine corrente.
Il metodo stepperValueChanged aggiornerà il modello di immagine pertinente impostando il suo rating su o giù.
Nel file .m di RootViewController importare ImageViewController e configurare i controller di visualizzazione per il controller della visualizzazione di pagina:
RootViewController.m
#import "ImageViewController.h" @implementation RootViewController - (void) viewDidLoad [super viewDidLoad]; [[visualizzazione automatica] setBackgroundColor: [UIColor blackColor]]; _modelArray = [NSMutableArray arrayWithObjects: [[ImageModel alloc] initWithImageName: @ "cat.jpg"], [[ImageModel alloc] initWithImageName: @ "DawnFlight.jpeg"], [[ImageModel alloc] initWithImageName: @ "James.jpg"] , [[ImageModel alloc] initWithImageName: @ "MOS_KIM.jpg"], [[ImageModel alloc] initWithImageName: @ "Pterophorus.jpg"], nil]; _pageViewController = [[UIPageViewController alloc] initWithTransitionStyle: UIPageViewControllerTransitionStyleScroll navigationOrientation: UIPageViewControllerNavigationOrientationHorizontal options: [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 50.0f] forKey: UIPageViewControllerOptionInterPageSpacingKey]]; _pageViewController.delegate = self; _pageViewController.dataSource = self;
Ci sono alcune cose che succedono qui. Per prima cosa, impostiamo il nostro colore di sfondo sul nero. Secondo, assegniamo init alla nostra paginaViewController con la transizione scollStyle, l'orientamento di navigazione orizzontale e un dizionario per le nostre opzioni. Il dizionario contiene un NSNumber che afferma che dovrebbe esserci una spaziatura di 50 punti tra ogni viewController. Quindi procediamo a impostarci come delegato e origine dati per la paginaViewController.
Successivamente, abbiamo bisogno di impostare una viewController iniziale per iniziare con:
RootViewController.m
_pageViewController.delegate = self; _pageViewController.dataSource = self; ImageViewController * imageViewController = [[ImageViewController alloc] init]; imageViewController.model = [_modelArray objectAtIndex: 0]; NSArray * viewControllers = [NSArray arrayWithObject: imageViewController]; [self.pageViewController setViewControllers: viewControllers direction: UIPageViewControllerNavigationDirectionForward animato: NO completamento: nil]; [self addedChildViewController: _pageViewController]; [self.view addSubview: _pageViewController.view]; [_pageViewController didMoveToParentViewController: self]; CGRect pageViewRect = self.view.bounds; pageViewRect = CGRectInset (pageViewRect, 40.0, 80.0f); self.pageViewController.view.frame = pageViewRect; self.view.gestureRecognizers = _pageViewController.gestureRecognizers;
Qui creiamo un nuovo controller di visualizzazione del contenuto, lo aggiungiamo a un array e quindi impostiamo tale array come proprietà viewControllers per il nostro pageController. Successivamente, aggiungiamo la paginaViewController come childViewController e quindi la paginaViewControllersView alla nostra. Diamo quindi un po 'di un inserto in modo che non occupa l'intera vista e impostare i nostri riconoscimenti di gesti a quello della paginaViewControllers in modo che tutto sia sincronizzato.
Infine, per completare la visualizzazione, è necessario aggiungere lo stepper e l'etichetta che descrive l'immagine:
RootViewController.m
self.view.gestureRecognizers = _pageViewController.gestureRecognizers; _rateStepper = [[UIStepper alloc] initWithFrame: CGRectMake (40, 680, 40, 30)]; [_rateStepper addTarget: self action: @selector (stepperValueChanged :) forControlEvents: UIControlEventValueChanged]; [_rateStepper setMinimumValue: 0]; [_rateStepper setMaximumValue: 10]; [_rateStepper setIncrementImage: [UIImage imageNamed: @ "arrowup"] forState: UIControlStateNormal]; [_rateStepper setDecrementImage: [UIImage imageNamed: @ "arrowdown"] forState: UIControlStateNormal]; [[visualizzazione automatica] addSubview: _rateStepper]; _imageLabel = [[UILabel alloc] initWithFrame: CGRectMake (0, 0, self.view.frame.size.width, 40)]; _imageLabel.backgroundColor = [UIColor clearColor]; _imageLabel.textColor = [UIColor whiteColor]; [_imageLabel setFont: [UIFont boldSystemFontOfSize: 20]]; [_imageLabel setAutoresizingMask: UIViewAutoresizingFlexibleWidth]; [_imageLabel setTextAlignment: NSTextAlignmentCenter]; ImageModel * model = [_modelArray objectAtIndex: 0]; _imageLabel.text = [NSString stringWithFormat: @ "% @ - Valutazione:% d", model.imageName, model.rating]; [[visualizzazione automatica] addSubview: _imageLabel];
La maggior parte di questo dovrebbe essere abbastanza semplice. La cosa principale a cui prestare attenzione qui è dove impostiamo le immagini di "incremento" e "decremento" per il controllo stepper. Dovrai trovare le tue immagini per questo, ma dovrebbe essere facile creare o trovare alcune icone gratuite su google. Se non puoi farlo, puoi semplicemente saltare la personalizzazione dello stepper.
Se ora costruiamo ed eseguiamo la nostra app, dovrebbe assomigliare a questa:
Questo è un buon inizio, ma le immagini non scorrono ancora e lo stepper si arresta in modo anomalo. Mancano anche gli indicatori di pagina. Riempiamo quegli spazi vuoti:
Dobbiamo implementare i metodi dell'origine dati che indicano alla paginaViewController quali caricatori di vista devono essere caricati prima e dopo quello corrente:
RootViewController.m
#pragma mark - #pragma mark - UIPageViewControllerDelegate Method - (UIViewController *) pageViewController: (UIPageViewController *) pageViewController viewControllerBeforeViewController: (UIViewController *) viewController ImageViewController * contentVc = (ImageViewController *) viewController; NSUInteger currentIndex = [_modelArray indexOfObject: [contentVc model]]; _vcIndex = currentIndex; [_rateStepper setValue: [[contentVc model] valutazione]]; ImageModel * model = [_modelArray objectAtIndex: _vcIndex]; [_imageLabel setText: [NSString stringWithFormat: @ "% @ - Valutazione:% d", model.imageName, model.rating]]; if (currentIndex == 0) return nil; ImageViewController * imageViewController = [[ImageViewController alloc] init]; imageViewController.model = [_modelArray objectAtIndex: currentIndex - 1]; return imageViewController; - (UIViewController *) pageViewController: (UIPageViewController *) pageViewController viewControllerAfterViewController: (UIViewController *) viewController ImageViewController * contentVc = (ImageViewController *) viewController; NSUInteger currentIndex = [_modelArray indexOfObject: [contentVc model]]; _vcIndex = currentIndex; [_rateStepper setValue: [[contentVc model] valutazione]]; ImageModel * model = [_modelArray objectAtIndex: _vcIndex]; [_imageLabel setText: [NSString stringWithFormat: @ "% @ - Valutazione:% d", model.imageName, model.rating]]; if (currentIndex == _modelArray.count - 1) return nil; ImageViewController * imageViewController = [[ImageViewController alloc] init]; imageViewController.model = [_modelArray objectAtIndex: currentIndex + 1]; return imageViewController;
Entrambi questi metodi sono abbastanza simili. Per prima cosa, otteniamo il viewController rilevante prima o dopo quello corrente (e lo lanciamo su un ImageViewController). Cerchiamo quindi di trovare dove l'indice di quel modello di viewController è in relazione al nostro array di modelli. Una volta trovato, impostiamo il nostro valore corrente vcIndex su currentIndex. Ci assicuriamo inoltre di aggiornare il valore corrente dello stepper e di aggiornare la stringa dell'etichetta per visualizzare il nome dell'immagine e il valore nominale correnti.
Se l'indice fosse fuori limite (determinato pari a 0 o il conteggio dell'array modello - 1), non restituiremo un nuovo controller di visualizzazione. Se è presente un modello da caricare, creiamo un nuovo ImageViewController, impostiamo il suo modello sul modello pertinente nell'array e restituiamo viewController.
Se si crea ed esegui ora, le pagine scorreranno, tuttavia manchiamo ancora della vista dell'indicatore di pagina. Abbiamo solo bisogno di implementare i seguenti metodi DataSource come di seguito:
RootViewController.m
#pragma mark - #pragma mark - UIPageViewControllerDataSource Method - (NSInteger) presentationCountForPageViewController: (UIPageViewController *) pageViewController return _modelArray.count; - (NSInteger) presentationIndexForPageViewController: (UIPageViewController *) pageViewController return 0;
È così facile Per il metodo count, restituiamo semplicemente il conteggio dell'array del modello e per l'indice corrente restituiamo semplicemente ciò di cui ha bisogno per iniziare, ovvero 0.
Tutto il duro lavoro è stato fatto! Per classificare le immagini, è sufficiente implementare il nostro metodo "stepperValueChanged" e aggiungere il seguente codice:
RootViewController.m
#pragma mark - #pragma mark - Private Methods - (void) stepperValueChanged: (id) sender ImageModel * model = [_modelArray objectAtIndex: _vcIndex]; [model setRating: [_ rateStepper value]]; [_imageLabel setText: [NSString stringWithFormat: @ "% @ - Valutazione:% d", model.imageName, model.rating]];
Otteniamo semplicemente il modello all'indice corrente, aggiorniamo il suo rating in base alla valutazione degli stepper e quindi aggiorniamo il testo dell'etichetta.
Costruisci ed esegui la tua applicazione ora e dovrebbe assomigliare a questa:
Abbiamo spiegato come configurare un PageViewController molto semplice usando il nuovo stile di transizione scroll senza l'uso di uno xib o storyboard. Questo dovrebbe darti una solida comprensione di come funziona PageViewController e permetterti di modificarlo per funzionare nelle tue applicazioni!