Använda ScrollStyle med UIPageViewController

En av de förändringar som introducerades med iOS 6 är möjligheten att använda UIPageViewController för att använda en rullningsanimering i stället för standardsidans vändstil. Läs vidare för att lära dig hur vi kan använda detta för att enkelt skapa en paginerad rullningsvy effekt!

För att utforska dessa förändringar skapar vi en "image rater" -applikation där användare kan svepa igenom olika bilder och ge betyg till var och en. Även om förutsättningen är grundläggande, kommer det att ge dig en bra chans att börja använda UIPageControl med den nya stilen.


Steg 1: Ställa in

Innan vi börjar behöver vi några bilder. Hoppa in i Wikipedia och ladda ner 5 olika bilder som är licensierade under en kreativ commons. Skapa ett nytt Xcode-projekt med en tom mall. Namnge det "ImageRater" eller något motsvarande. Se till att den inriktade enheten är inställd på iPad, storybording är avstängd och ARC är på.

Detta projekt kommer att utformas för att användas endast i landskapsorientering. Innan vi börjar öppnar du projektinställningarna och väljer bara liggande orienteringar.


Steg 2: Skapa bildmodellen och View Controller

Därefter måste vi skapa modellobjektet och visa kontrollen ansvarig för att visa bilden. Skapa en ny klass som heter "ImageModel" som arv från NSObject. Detta kommer att vara en enkel modellklass som innehåller en sträng som representerar bildfilnamnet och ett heltal som representerar bilden "rating":

ImageModel.h

 @interface ImageModel: NSObject - (id) initWithImageName: (NSString *) imageName; @property (nonatomic, strong) NSString * imageName; @property (nonatomic) NSInteger rating; @slutet

Vi har också skapat en anpassad init-metod som gör det enklare att skapa dessa med ett bildnamn. I .m-filen implementerar init-metoden så:

ImageModel.m

 @implementation ImageModel - (id) initWithImageName: (NSString *) imageName self = [super init]; om (själv) _imageName = imageName; _rating = 0;  återvänd själv 

Utsikten kontrollern som kommer att visa bilden kommer också att vara mycket enkelt. Skapa en ny klass som heter ImageViewController (ärver UIViewController) och ge den följande egenskaper (såväl som import av ImageModel.h):

ImageViewController.h

 #import "ImageModel.h" @interface ImageViewController: UIViewController @property (nonatomic, strong) UIImageView * imageView; @property (nonatomic, strong) UILabel * etikett; @property (nonatomic, strong) ImageModel * modell; @slutet

Och i .m-filen, lägg till följande kod:

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]]; [[självvisning] addSubview: _imageView]; 

När vyn laddas, ställer vi in ​​bakgrundsfärgen och ställer in bildvyn.


Steg 3: Ställ in PageViewController

Skapa en ny klass som heter "RootViewController" (arv från UIViewController). Det här kommer att vara där åtgärden händer. Den kommer att innehålla PageViewController, etiketten som visar namnet och rankningen av bilden, liksom en stegning som gör det möjligt för användaren att ställa in betyget för bilden.

När du har skapat klassen öppnar du appdelegationens huvudfiler, importerar klassen RootViewController och ställer in den som en egenskap:

AppDelegate.h

 #import "RootViewController.h" @interface AppDelegate: UIResponder  @property (strong, nonatomic) UIWindow * fönster; @property (strong, nonatomic) RootViewController * viewController; @slutet

Och i implementeringsfilen ställer du in den som root view controller:

AppDelegate.m

 - (BIA) -applikation: (UIApplication *) ansökan didFinishLaunchingWithOptions: (NSDictionary *) launchOptions self.window = [[UIWindow alloker] initWithFrame: gränser för [[UIScreen mainScreen]]; // Åsidosätt punkt för anpassning efter applikationsstart. self.viewController = [[RootViewController alloc] init]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; returnera JA; 

Öppna .h-filen i RootViewController och ge den följande egenskaper och anpassa den till UIPageViewControllerDataSource och Delegate-metoderna:

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) avsändare; @slutet

PageViewController kommer att ansvara för att visa ImageViewControllers och modellmatrisen kommer att ansvara för att lagra imageModel-objekten. VcIndex kommer att ansvara för att hålla reda på det aktuella sidindexet. RateStepper tillåter användaren att betygsätta en bild upp eller ner. ImageLabel visar namnet och betyget för den aktuella bilden.

StepperValueChanged-metoden kommer att uppdatera den aktuella bildmodellinställningen sin rating upp eller ner.

I .m-filen i RootViewController importerar du ImageViewController och ställer in bildkontrollerna för sidvisningsregulatorn:

RootViewController.m

 #import "ImageViewController.h" @implementation RootViewController - (void) viewDidLoad [super viewDidLoad]; [[self view] setBackgroundColor: [UIColor blackColor]]; _modelArray = [NSMutableArray arrayWithObjects: [[ImageModel allokera initWithImageName: @ "cat.jpg"], [[ImageModel allokera initWithImageName: @ "DawnFlight.jpeg"], [[ImageModel alloc] initWithImageName: @ "James.jpg"] , [[ImageModel alloc] initWithImageName: @ "MOS_KIM.jpg"], [[ImageModel allokera] initWithImageName: @ "Pterophorus.jpg"], noll]; _pageViewController = [[UIPageViewController alloc] initWithTransitionStyle: UIPageViewControllerTransitionStyleScroll navigationOrientation: UIPageViewControllerNavigationOrientationHorizontal options: [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 50.0f] forKey: UIPageViewControllerOptionInterPageSpacingKey]]; _pageViewController.delegate = self; _pageViewController.dataSource = self;

Det finns några saker som händer här. Först ställer vi vår bakgrundsfärg till svart. För det andra fördelar vi init vår pageViewController med scollStyle-övergången, den horisontella navigationsriktningen och en ordlista för våra alternativ. Ordboken innehåller en NSNumber som säger att det ska finnas ett avstånd på 50 punkter mellan varje viewController. Vi fortsätter sedan att ställa oss som delegat och datakälla för pageViewController.

Därefter måste vi inrätta en initial vykontroll för att börja med:

RootViewController.m

 _pageViewController.delegate = self; _pageViewController.dataSource = self; ImageViewController * imageViewController = [[ImageViewController tilldela] init]; imageViewController.model = [_modelArray objectAtIndex: 0]; NSArray * viewControllers = [NSArray arrayWithObject: imageViewController]; [self.pageViewController setViewControllers: viewControllers riktning: UIPageViewControllerNavigationDirectionForward animated: NO completion: nil]; [self addChildViewController: _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;

Här skapar vi en ny innehållsvykontroll, lägger till den i en matris och ställer sedan in den här matrisen som egenskapen viewControllers för vår pageController. Därefter lägger vi till pageViewController som vår childViewController och sedan pageViewControllersView till vår egen. Vi ger det lite av ett inset så att det inte tar upp hela vyn och ställer in våra gestkännare till sidanViewViewControllers så att allt är synkroniserat.

Slutligen, för att avsluta vyn måste vi lägga till steg och etikett som beskriver bilden:

RootViewController.m

 self.view.gestureRecognizers = _pageViewController.gestureRecognizers; _rateStepper = [[UIStepper alloc] initWithFrame: CGRectMake (40, 680, 40, 30)]; [_rateStepper addTarget: självåtgärd: @selector (stepperValueChanged :) forControlEvents: UIControlEventValueChanged]; [_rateStepper setMinimumValue: 0]; [_rateStepper setMaximumValue: 10]; [_rateStepper setIncrementImage: [UIImage imageNamed: @ "arrowup"] forState: UIControlStateNormal]; [_rateStepper setDecrementImage: [UIImage imageNamed: @ "arrowdown"] forState: UIControlStateNormal]; [[självvisning] 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: @ "% @ - Betyg:% d", model.imageName, model.rating]; [[självvisning] addSubview: _imageLabel]; 

Det mesta av detta borde vara ganska enkelt. Det viktigaste att uppmärksamma här är där vi ställer in "inkrement" och "minskning" bilder för stegreglaget. Du måste hitta dina egna bilder för detta, men det ska vara lätt att göra eller hitta några gratis ikoner på google. Om du inte kan göra det, kan du helt enkelt hoppa över att anpassa steget.

Om vi ​​bygger och kör vår app nu ska det se ut så här:

Det här är en bra start, men bilderna rullar inte ännu och steppen kraschar appen. Vi saknar också sidindikatorerna. Låt oss fylla i dessa ämnen:


Steg 4: Slutför PageViewController

Vi behöver implementera datakällans metoder som berättar för pageViewController vilka visningsstyrare ska laddas före och efter den nuvarande:

RootViewController.m

 #pragma markera - #pragma markera - UIPageViewControllerDelegate Method - (UIViewController *) pageViewController: (UIPageViewController *) pageViewController viewControllerBeforeViewController: (UIViewController *) viewController ImageViewController * contentVc = (ImageViewController *) viewController; NSUInteger currentIndex = [_modelArray indexOfObject: [contentVc-modell]]; _vcIndex = currentIndex; [_rateStepper setValue: [[contentVc model] rating]]; ImageModel * model = [_modelArray objectAtIndex: _vcIndex]; [_imageLabel setText: [NSString stringWithFormat: @ "% @ - Betyg:% d", model.imageName, model.rating]]; om (currentIndex == 0) returnera nil;  ImageViewController * imageViewController = [[ImageViewController alloc] init]; imageViewController.model = [_modelArray objectAtIndex: currentIndex - 1]; returnera imageViewController;  - (UIViewController *) pageViewController: (UIPageViewController *) pageViewController viewControllerAfterViewController: (UIViewController *) viewController ImageViewController * contentVc = (ImageViewController *) viewController; NSUInteger currentIndex = [_modelArray indexOfObject: [contentVc-modell]]; _vcIndex = currentIndex; [_rateStepper setValue: [[contentVc model] rating]]; ImageModel * model = [_modelArray objectAtIndex: _vcIndex]; [_imageLabel setText: [NSString stringWithFormat: @ "% @ - Betyg:% d", model.imageName, model.rating]]; om (currentIndex == _modelArray.count - 1) return nil;  ImageViewController * imageViewController = [[ImageViewController alloc] init]; imageViewController.model = [_modelArray objectAtIndex: currentIndex + 1]; returnera imageViewController; 

Båda dessa metoder är ganska lika. Först får vi den relevanta viewController före eller efter den aktuella (och kasta den till en ImageViewController). Vi ser då ut för att hitta var indexet för den viewController-modellen ligger i förhållande till vår modellmatris. När vi hittat, ställer vi in ​​vårt nuvarande vcIndex-värde till nuvarandeIndex. Vi ser också till att uppdatera stegarens nuvarande värde och uppdatera etikettsträngen för att visa det aktuella bildnamnet och värdet för värdet.

Om indexet skulle vara obegränsat (bestämt med lika med 0 eller antalet modeller i array-1), returnerar vi inte en ny bildkontroll. Om det finns en modell som ska laddas, skapar vi en ny ImageViewController, ställer in modellen till den relevanta modellen i matrisen och returnerar viewController.

Om du bygger och kör nu bläddrar sidorna, men vi saknar fortfarande sidindikatorvyn. Vi behöver bara implementera följande dataSource-metoder enligt nedan:

RootViewController.m

 #pragma mark - #pragma mark - UIPageViewControllerDataSource Method - (NSInteger) presentationCountForPageViewController: (UIPageViewController *) pageViewController return _modelArray.count;  - (NSInteger) presentationIndexForPageViewController: (UIPageViewController *) pageViewController return 0; 

Det är så enkelt. För räknemetoden returnerar vi helt enkelt räkningen av modelluppsättningen och för det aktuella indexet returnerar vi helt enkelt vad den behöver för att börja vid, vilket är 0.


Steg 5: Betygsätt bilderna

Allt hårt arbete har gjorts! För att rangordna bilderna, implementera bara vår "stepperValueChanged" -metod och lägg till följande kod:

RootViewController.m

 #pragma mark - #pragma mark - Privata metoder - (void) stepperValueChanged: (id) avsändare ImageModel * model = [_modelArray objectAtIndex: _vcIndex]; [modell setRating: [_ rateStepper value]]; [_imageLabel setText: [NSString stringWithFormat: @ "% @ - Betyg:% d", model.imageName, model.rating]]; 

Vi får helt enkelt modellen vid det aktuella indexet, uppdatera dess betyg baserat på steppers betyg och uppdatera sedan etiketttexten.

Bygg och kör din ansökan nu och det ska se ut så här:


Sammanfatta

Vi har täckt hur du ställer in en mycket enkel PageViewController med den nya rullningsövergångsstilen utan att använda en xib eller storyboard. Detta borde ge dig en gedigen förståelse för hur SidViewController fungerar och låter dig ändra det för att fungera i dina egna applikationer!