I'm trying to display an entire pageContentView within a SubView on a rootViewController. I'm able to see the pageView but it doesn't auto-resize correctly to fit the SubView, it only shows a cutoff portion of the pageContentView
Here's what it looks like
Here's what it should look like
I can't figure out how to resize the pageView so it display correctly in a subView.
RootViewController.h
#import <UIKit/UIKit.h>
#import "PageContentViewController.h"
#class PageContentViewController;
#interface CLDViewController : UIViewController <UIPageViewControllerDataSource>
#property (weak, nonatomic) IBOutlet UIView *subViewRoot;
- (IBAction)startWalkthrough:(id)sender;
#property (strong, nonatomic) UIPageViewController *pageViewController;
#property (strong, nonatomic) NSArray *pageTitles;
#property (strong, nonatomic) NSArray *pageImages;
#property (strong,nonatomic) PageContentViewController *bounds;
#end
ViewDidLoad and required methods for UIPageViewController in RootController
- (void)viewDidLoad
{
[super viewDidLoad];
_pageTitles = #[#"Over 200 Tips and Tricks", #"Discover Hidden Features", #"Bookmark Favorite Tip", #"Free Regular Update"];
_pageImages = #[#"page1.png", #"page2.png", #"page3.png", #"page4.png"];
// Create page view controller
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
//Trying to setup the pageViewContoller view to be inside the subview (subViewRoot)
self.pageViewController.view.frame = self.subViewRoot.bounds;
[self addChildViewController:_pageViewController];
[self.subViewRoot addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
return nil;
}
// Create a new view controller and pass suitable data.
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
pageContentViewController.imageFile = self.pageImages[index];
pageContentViewController.titleText = self.pageTitles[index];
pageContentViewController.pageIndex = index;
return pageContentViewController;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageTitles count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [self.pageTitles count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
PageContentViewController.m
-viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
self.backgroundImageView.image = [UIImage imageNamed:self.imageFile];
self.titleLabl.text = self.titleText;
}
Has anyone ran into this situation before? What did you do?
Thanks for the help!
Since you are setting the frame of your UIPageViewController to the frame of that 'subview' placeholder view, you need to make sure that the frame for the placeholder will be accurate by when the view is loaded. ViewControllers loaded from xibs don't generally have a useful frame until their view is added somewhere, and the same goes for their subviews. viewWillAppear is usually the soonest you can be sure your viewController's view to be set correctly.
Disabling auto-layout will work, but auto layout can be a nice feature once you learn how to use it. In this case, you can add constraints from subViewRoot to its parent view - Leading, Trailing, Top and Bottom. Control dragging from the subViewRoot to the parent is an easy shortcut.
I was able to get my view laid out as I wanted using constraints on the PageContentViewController and also adding constraints to the SubView on the RootViewController. (As Acey suggested)
I did this by selecting "resolve auto-layout issues" --> Reset to suggested auto layout constraints.
Then also ctr-clking inside the view and setting width and height constraints. I can even change the orientation and the layout is what I expect.
for anyone struggling with this feel free to send a pm or comment here.
Related
Basically, I am making a page app, which use UIPageViewController. When the user scrolls the page, they can see different content. The problem now is, when I scroll the page, the first and second page works properly, and the index is correct. But when I scroll to the third page, the index keeps at "1", and don't change afterwards. And the other page keeps the appearance of the second page, whose index is "1".
I was following the tutorial: http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/
My code:
View Controller.h
#import <UIKit/UIKit.h>
#import "PageContentViewController.h"
#import "PageViewController.h"
#interface ViewController : UIViewController<UIPageViewControllerDataSource, UIPageViewControllerDelegate>
#property (strong, nonatomic) PageViewController *pageViewController;
#property (strong, nonatomic) NSArray *pageTitles;
#end
View Controller.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.pageTitles = #[#"First Page", #"Second Page", #"Third Page"];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
if ([self.pageTitles count])
{
PageContentViewController *startingViewController = [self viewControllerAtIndex: 0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
}
- (PageContentViewController *) viewControllerAtIndex: (NSUInteger)index{
if (index < [self.pageTitles count])
{
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
pageContentViewController.titleText = self.pageTitles[index];
NSLog(#"%li", index);
UIColor *backgroundColor;
switch (index) {
case 0:
backgroundColor = [UIColor greenColor];
break;
case 1:
backgroundColor = [UIColor blueColor];
break;
case 2:
backgroundColor = [UIColor purpleColor];
break;
default:
break;
}
pageContentViewController.backgroundColor = backgroundColor;
return pageContentViewController;
}
return nil;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController *)viewController).pageIndex;
if (index == NSNotFound)
{
return nil;
}
index++;
if (index == [self.pageTitles count])
{
return nil;
}
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController *)viewController).pageIndex;
if (index == 0 || index == NSNotFound)
{
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (NSInteger) presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [self.pageTitles count];
}
- (NSInteger) presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Page Content View Controller.h
#import <UIKit/UIKit.h>
#interface PageContentViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *backgroundView;
#property (weak, nonatomic) IBOutlet UILabel *titleLable;
#property (nonatomic) NSUInteger pageIndex;
#property (strong, nonatomic) NSString *titleText;
#property (strong, nonatomic) UIColor *backgroundColor;
#end
Page Content View Controller.m
#import "PageContentViewController.h"
#interface PageContentViewController ()
#end
#implementation PageContentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.titleLable.text = self.titleText;
[self.backgroundView setBackgroundColor:self.backgroundColor];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
In viewControllerAtIndex:, you need to set the value of pageIndex property of the pageContentViewController:
pageContentViewController.pageIndex = index;
I have 2 view controllers. viewController1 has a UILabel called nameLabel which I want to set in a different class, viewController2.
I try calling this code from viewController2.
Content1ViewController *viewController1 = [Content1ViewController new];
viewController1.nameLabel.text = #"HELLO";
NSLog(#"%#",viewController1.nameLabel);
However, the viewController1 nameLabel doesn't change when I call the code? Also the NSLog returns "null"?? Can someone tell me why this is happening and also how I can change the nameLabel from a different class? Thanks!
Controls are not initialized when you manually create the instance. This is done on a later stage of view controller life cycle.
If I'm not mistaken, first event where you will see controls initialized is viewDidLoad
Something you can do is adding a NSString property named (let's say) nameLabelText and do nameLabel.text = nameLabelText; on viewDidLoad
You need to take the same instance of viewController which was on the window. If you are pushing viewController2 into navigation controller stack then get instance of viewController1 from navigation stack and then try to set the label.
If you are using present modal then use presentingViewController instance of viewController2 in order to access instance of viewController1 like
viewController1 *controller = [viewController2 presentingViewController];
[controller.nameLabel setText:#"WhatEver"];
Where have you set the property for namelabel?
Did you use Interface Builder (XIB or Storyboard) or have you done it all in code?
If the you did it in InterfaceBuilder than
[Content1ViewController new]
is the wrong approach.
For XIB-Files you should use
initWithNibName:(NSString *)nibName
bundle:(NSBundle *)nibBundle
and if your ViewController has been defined in a storyboard you should use
instantiateViewControllerWithIdentifier:(NSString *)identifier
from UIStoryboard.
But as Claudio Redi already said the earliest point where you will be able to access the UILabel will be in viewDidLoad
If everything in code, you should put
[self setNameLabel:[[UILabel alloc] initWithFrame:CGRectMake(50.0f,50.0f,100.0f,100.0f)];
in the init-Method of your ViewController.
//
// ViewController.m
// UIPageViewControllerDemo
//
// Created by YunYi1118 on 15/5/20.
// Copyright (c) 2015年 Xiaoyi. All rights reserved.
//
#import "ViewController.h"
#import "MoreViewController.h"
#interface ViewController () <UIPageViewControllerDataSource, UIPageViewControllerDelegate>
#property (strong, nonatomic) UIPageViewController *pageController;
#property (strong, nonatomic) NSArray *pageContent;
#end
#implementation ViewController
#synthesize pageContent = _pageContent;
#synthesize pageController = _pageController;
- (void)viewDidLoad {
[super viewDidLoad];
[self createContentPages];
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin] forKey:UIPageViewControllerOptionSpineLocationKey];
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:options];
_pageController.dataSource = self;
_pageController.view.frame = self.view.bounds;
MoreViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:_pageController];
[self.view addSubview:_pageController.view];
}
- (MoreViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (self.pageContent.count == 0 || index >= self.pageContent.count) {
return nil;
}
MoreViewController *dataViewController = [[MoreViewController alloc] init];
dataViewController.dataObject = [self.pageContent objectAtIndex:index];
return dataViewController;
}
- (void)createContentPages
{
NSMutableArray *pageStrings = [NSMutableArray array];
for (int i = 1; i < 11; i++) {
NSString *contentString = [[NSString alloc] initWithFormat:#"Chapter%d, This is the page %d of content displayed using UIPageViewController ",i,i];
[pageStrings addObject:contentString];
}
self.pageContent = [NSArray arrayWithArray:pageStrings];
}
#pragma mark - delegate
- (NSUInteger)indexOfViewController:(MoreViewController *)viewController
{
return [self.pageContent indexOfObject:viewController.dataObject];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(MoreViewController *)viewController];
if (index == 0 || index == NSNotFound) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(MoreViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == self.pageContent.count) {
return nil;
}
return [self viewControllerAtIndex:index];
}
#end
I'm trying to add UIPageViewController to my RootViewController in code. I removed storyboard file according to
Xcode 5 without Storyboard and ARC
and adding “regular” ViewController works perfectly. I adoped methods according to UIPageViewControllerDataSource
Also I tried to simplify logic (instead of implementing ModelController from starting PageView project I add showVCWithIndex: method to pick 1 of 3 VC from vcArray and write it to Mutable Array with 1 VC. Hope you can tell me if I was right or wrong about that.
.m
#import "RootPageViewController.h"
#import "ViewController0.h"
#import "ViewController1.h"
#import "ViewController2.h"
#interface RootPageViewController ()
#property (strong, nonatomic) ViewController0 *vController0;
#property (strong, nonatomic) ViewController1 *vController1;
#property (strong, nonatomic) ViewController2 *vController2;
#property (strong, nonatomic) UIPageViewController *pageViewController;
#property (strong, nonatomic) NSArray *vcArray;
#property (strong, nonatomic) NSMutableArray *viewController;
#end
#implementation RootPageViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.dataSource = self;
_vController0 = [[ViewController0 alloc] init];
_vController1 = [[ViewController1 alloc] init];
_vController2 = [[ViewController2 alloc] init];
NSUInteger index = 0;
NSMutableArray *viewController = [NSMutableArray arrayWithObjects:[self showVCWithIndex:index], nil];
[self.pageViewController setViewControllers:viewController
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
CGRect pageViewRect = self.view.bounds;
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [self.vcArray indexOfObject:viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self showVCWithIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self.vcArray indexOfObject:viewController];
if (index == 2 || index == NSNotFound) {
return nil;
}
index++;
return [self showVCWithIndex:index];
}
- (UIViewController *)showVCWithIndex: (NSUInteger)index
{
self.vcArray = [NSArray arrayWithObjects: _vController0, _vController1, _vController2, nil];
UIViewController *currentVC = [self.vcArray objectAtIndex:index];
return currentVC;
}
#end
EDIT
got the solution (this code works, but I'm not sure if I am 100% right)
When you call...
[self.pageViewController setViewControllers:[vcArray objectAtIndex:0]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
... you are setting a nil view controller to the pagination view controller.
[vcArray objectAtIndex:0] points to _vController0 which is, in that moment, nil (you haven't instantiated it yet).
Before set you view controllers into the pagination, you must get it from the storyboard using [self.storyboard instatiateViewControllerWithIdentifier:#"YourViewControllerIdentifier"] or simply calling a alloc init, if you are using Xibs.
When you set the view controllers in your UIPageViewController it has to be an array with only one view controller. The method -setViewControllers:direction:animated:completion: is so misleading. I had the same problem as you when I created a page view controller for the first time.
To allow your page view controller to display other view controllers you return them in the UIPageViewControllerDataSource methods -pageViewController:viewControllerBeforeViewController: and -pageViewController:viewControllerAfterViewController:.
I have an app that presents a PageViewController tutorial scene. In my settings page I have a button that returns to the PageViewController, labeled IntroViewController.
When the tutorial first appears, it works fine. But when I go back, the dots at the base of the PageViewController disappear. Any idea why this happens?
Here is the IntroViewController.m
#import "IntroViewController.h"
#interface IntroViewController ()
#end
#implementation IntroViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Create the data model
_pageTitles = #[#"Over 200 Tips and Tricks", #"Discover Hidden Features", #"Bookmark Favorite Tip", #"Another one!"];
if ([[UIScreen mainScreen] bounds].size.height == 568) {
_pageImages = #[#"IntroExpand.png", #"IntroSlow.png", #"IntroImport.png", #"IntroRename.png"];
}
else {
_pageImages = #[#"IntroExpand.png", #"IntroSlow.png", #"IntroImport.png", #"IntroRename.png"];
}
// Create page view controller
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 5);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
[self.view bringSubviewToFront:self.ready];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)ready:(id)sender { //this is the action that the user does to dismiss the tutorial and go to the first scene
UIStoryboard *storyBoard;
storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController =
[storyBoard instantiateViewControllerWithIdentifier:#"NavigationViewController"];
[self presentViewController:viewController animated:YES completion:nil];
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageTitles count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
return nil;
}
// Create a new view controller and pass suitable data.
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
pageContentViewController.imageFiles = self.pageImages[index];
pageContentViewController.titleText = self.pageTitles[index];
pageContentViewController.pageIndex = index;
return pageContentViewController;
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [self.pageTitles count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
#end
Here is the IntroViewController.h
#import <UIKit/UIKit.h>
#import "PageContentViewController.h"
#interface IntroViewController : UIViewController <UIPageViewControllerDataSource>
- (IBAction)ready:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *ready;
#property (weak, nonatomic) UIPageViewController *pageViewController;
#property (strong, nonatomic) NSArray *pageTitles;
#property (strong, nonatomic) NSArray *pageImages;
#end
And here is the button/action that takes the user from the settings page to the tutorial. I've tried different segues, modal, push, etc., and they all have the same problem of not displaying the dots when the user returns to the tutorial
- (IBAction)tutorialReplay:(id)sender {
UIStoryboard *storyBoard;
storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController =
[storyBoard instantiateViewControllerWithIdentifier:#"IntroViewController"];
[self presentViewController:viewController animated:YES completion:nil];
}
Let me know if I need to add more code to help. Thanks all.
In my custom UIPageViewController class:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
self.model = [[BSTCMWelcomingPageViewModel alloc] init];
self.dataSource = self.model;
self.delegate = self;
self.pageControl = [UIPageControl appearance];
self.pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
self.pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
}
return self;
}
Then I programmatically set the current ViewController when a button is hit:
- (void)scrollToNext
{
UIViewController *current = self.viewControllers[0];
NSInteger currentIndex = [self.model indexForViewController:current];
UIViewController *nextController = [self.model viewControllerForIndex:++currentIndex];
if (nextController) {
NSArray *viewControllers = #[nextController];
// This changes the View Controller, but PageControl doesn't update
[self setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
//Nothing happens!
[self.pageControl setCurrentPage:currentIndex];
//Error: _installAppearanceSwizzlesForSetter: Not a setter!
[self.pageControl updateCurrentPageDisplay];
}
}
If I can't do this with the UIPageControl that "belongs" to my UIPageViewController I will just try to make my own. But it would be nice if this was possible tho!
to update your UIPageControl indicator, you need to implement one data source method of UIPageViewController (the UIPageViewControllerDataSource method) :
-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
This method is responsible for updating the page control indicator (when you use UIPageViewController). You only need to return the currentpage value in this method. The Method gets called by default when you use/make a call for setViewControllers on your custom UIPageViewController.
So the chunk of code that you need to write is:
- (void)scrollToNext
{
UIViewController *current = self.viewControllers[0];
NSInteger currentIndex = [self.model indexForViewController:current];
UIViewController *nextController = [self.model viewControllerForIndex:++currentIndex];
if (nextController) {
NSArray *viewControllers = #[nextController];
// This changes the View Controller and calls the presentationIndexForPageViewController datasource method
[self setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return currentIndex;
}
Hope this solves your problem. :)
As mentioned in accepted answer, you need to implement
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
But for me it was enough to use it like this:
Objective-C:
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
// The selected item reflected in the page indicator.
return [self.controllers indexOfObject:[pageViewController.viewControllers firstObject]];
}
Swift 3+:
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
guard let index = viewControllers?.index(of: (pageViewController.viewControllers?.first)!) else { return 0 }
return index
}
Without the need to remember the current index. Where self.controllers is an NSArray of UIViewControllers displayed in given UIPageViewController. I'm not sure how exactly your BSTCMWelcomingPageViewModel works, but it should be easy to adjust.
Xamarin/C# Solution
I had this problem in Xamarin, here is my version of #micromanc3r's solution:
public class PageViewControllerDataSource : UIPageViewControllerDataSource
{
UIViewController[] pages;
public PageViewControllerDataSource(UIViewController[] pages)
{
this.pages = pages;
}
...
public override nint GetPresentationIndex(UIPageViewController pageViewController)
{
return Array.IndexOf(pages, pageViewController.ViewControllers[0]);
}
}
SWIFT 4.2
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
guard let currentController = pageViewController.viewControllers?.first else {
return 0 }
guard let index = viewControllerList.index(of: currentController) else { return 0 }
return index
}
A page indicator will be visible if both methods are implemented, transition style is UIPageViewControllerTransitionStyleScroll and navigation orientation is UIPageViewControllerNavigationOrientationHorizontal. Both methods are called in response to a setViewControllers:... call, but the presentation index is updated automatically in the case of gesture-driven navigation.
(NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(6_0);: The number of items reflected in the page indicator.
(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(6_0);: The selected item reflected in the page indicator.
The answer above, given by aansul, works.
Note : Don't forget to set the pageViewController's Transition style to Scroll instead of Page Curl. Otherwise it won't work.
// ViewController.h File
#import <UIKit/UIKit.h>
#import "PageContentViewController.h"
#interface ViewScreen : UIViewController<UIPageViewControllerDataSource,UIPageViewControllerDelegate>
- (IBAction)Startwalkthrough:(id)sender;
#property(strong, nonatomic)UIPageViewController *pageViewController;
#property(strong, nonatomic)NSArray * pageTitles;
#property(strong,nonatomic)NSArray * pageImages;
#end
// ViewController.m File
#import "ViewScreen.h"
#interface ViewScreen ()
#end
#implementation ViewScreen
#synthesize pageTitles,pageImages;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
pageTitles =#[#"dianna",#"images",#"image",#"i1",#"hulk1",#"assasins"];
pageImages =#[#"dianna",#"images",#"image",#"i1",#"hulk1",#"assasins"];
self.pageViewController =[self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource=self;
PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray * viewController =#[startingViewController];
[self.pageViewController setViewControllers:viewController direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
-(IBAction)Startwalkthrough:(id)sender
{
PageContentViewController * startingViewController =[self viewControllerAtIndex:0];
NSArray * viewControllers =#[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
}
- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
return nil;
}
// Create a new view controller and pass suitable data.
PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageContentViewController"];
pageContentViewController.imageFile = self.pageImages[index];
pageContentViewController.titletext = self.pageTitles[index];
pageContentViewController.pageIndex = index;
return pageContentViewController;
}
#pragma mark - Page View Controller Data Source
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index =((PageContentViewController *) viewController).pageIndex;
if (index == NSNotFound) {
return nil;
}
index--;
if (index ==[self.pageTitles count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageTitles count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
-(NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{
return [self.pageTitles count];
}
-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
#end
// Second File
PageViewController.h File
#import <UIKit/UIKit.h>
#interface PageContentViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *txtLabel;
#property (strong, nonatomic) IBOutlet UIImageView *backgroundImageView;
#property NSUInteger pageIndex;
#property NSString *titletext;
#property NSString * imageFile;
#end
// SecondFile.M File
#import "PageContentViewController.h"
#interface PageContentViewController ()
#end
#implementation PageContentViewController
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self =[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
//
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.backgroundImageView.image =[UIImage imageNamed:self.imageFile];
self.txtLabel.text =self.titletext;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Make sure to set the currentIndex BEFORE you call setViewControllers