Note that there are some explanatory texts on larger screens.

plurals
  1. PONeed help for pushing a view in UIScrollView / UIPageControl on storyboard
    primarykey
    data
    text
    <p>I'm trying to implement UIScrollView with UIPageControl on storyboard to display multiple views. All the examples, tutorials or informations I found are using xib and not storyboard. I tried to adapt Apple's sample code but I'm missing something. As you can see, it is quite simple.</p> <p><img src="https://i.stack.imgur.com/JWQgL.png" alt="enter image description here"></p> <p>However, either I get an error in ContentController.m <strong><em>-[NSNull view]: unrecognized selector sent to instance 0x129acd8</em></strong> when I test <strong><em>if (controller.view.superview == nil)</em></strong> where I push the view (see below after the first half of code).</p> <p>Or only the UIScrollView and UIPageControl are working and I am not able to push the view in the UIScrollView:</p> <p><img src="https://i.stack.imgur.com/MAK8m.png" alt="enter image description here"></p> <p>I know it's a simple question, however I spent many hours on this and any help will be appreciated.</p> <p>I post the full code as it may help someone when resolved like a kind of tutorial. I will correct the code if/when needed according to contributions.</p> <p>Thanks in advance</p> <p><strong>AppDelegate.h</strong></p> <pre><code>// Nothing special as I don't want to manage it through application delegate @interface AppDelegate : UIResponder &lt;UIApplicationDelegate&gt; @property (strong, nonatomic) UIWindow *window; @end </code></pre> <p><strong>AppDelegate.m</strong></p> <pre><code>// Nothing special as I don't want to manage it through application delegate #import "AppDelegate.h" @implementation AppDelegate @synthesize window = _window; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { return YES; } - (void)applicationWillResignActive:(UIApplication *)application { } - (void)applicationDidEnterBackground:(UIApplication *)application { } - (void)applicationWillEnterForeground:(UIApplication *)application { } - (void)applicationDidBecomeActive:(UIApplication *)application { } - (void)applicationWillTerminate:(UIApplication *)application { } @end </code></pre> <p><strong>ContentController.h</strong></p> <pre><code>// From Apple's PageControl sample code #import &lt;UIKit/UIKit.h&gt; @interface ContentController : UIViewController &lt;UIScrollViewDelegate&gt; { UIScrollView *scrollView; UIPageControl *pageControl; NSMutableArray *viewControllers; BOOL pageControlUsed; } @property (nonatomic, retain) IBOutlet UIScrollView *scrollView; @property (nonatomic, retain) IBOutlet UIPageControl *pageControl; @property (nonatomic, retain) NSMutableArray *viewControllers; - (IBAction)changePage:(id)sender; @end </code></pre> <p><strong>ContentController.m</strong></p> <pre><code>// From Apple's PageControl sample code #import "AppDelegate.h" #import "ContentController.h" #import "MyViewController.h" // Private methods @interface ContentController (PrivateMethods) - (void)loadScrollViewWithPage:(int)page; - (void)scrollViewDidScroll:(UIScrollView *)sender; @end @implementation ContentController @synthesize scrollView, pageControl, viewControllers; static NSUInteger kNumberOfPages = 6; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.navigationController.navigationBar.hidden=YES; // view controllers are created lazily in the meantime, load the array with // placeholders which will be replaced on demand NSMutableArray *controllers = [[NSMutableArray alloc] init]; for (unsigned i = 0; i &lt; kNumberOfPages; i++) { [controllers addObject:[NSNull null]]; } self.viewControllers = controllers; // a page is the width of the scroll view scrollView.pagingEnabled = YES; scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height); scrollView.showsHorizontalScrollIndicator = NO; scrollView.showsVerticalScrollIndicator = NO; scrollView.scrollsToTop = NO; scrollView.delegate = self; pageControl.numberOfPages = kNumberOfPages; pageControl.currentPage = 0; // pages are created on demand // load the visible page // load the page on either side to avoid flashes when the user starts scrolling [self loadScrollViewWithPage:0]; [self loadScrollViewWithPage:1]; } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.pageControl=nil; self.pageControl = nil; self.viewControllers = nil; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } - (void)loadScrollViewWithPage:(int)page { if (page &lt; 0) return; if (page &gt;= kNumberOfPages) return; // replace the placeholder if necessary MyViewController *controller = [viewControllers objectAtIndex:page]; if ((NSNull *)controller == [NSNull null]) // &lt;== *** HERE SEEMS TO BE THE ERROR *** { controller = [[MyViewController alloc] initWithPageNumber:page initWithNibName:nil bundle:nil]; [viewControllers replaceObjectAtIndex:page withObject:controller]; } // add the controller's view to the scroll view if (controller.view.superview == nil) { CGRect frame = scrollView.frame; frame.origin.x = frame.size.width * page; frame.origin.y = 0; controller.view.frame = frame; [scrollView addSubview:controller.view]; } } - (void)scrollViewDidScroll:(UIScrollView *)sender { // We don't want a "feedback loop" between the UIPageControl and the scroll delegate in // which a scroll event generated from the user hitting the page control triggers updates from // the delegate method. We use a boolean to disable the delegate logic when the page control is used. if (pageControlUsed) { // do nothing - the scroll was initiated from the page control, not the user dragging return; } // Switch the indicator when more than 50% of the previous/next page is visible CGFloat pageWidth = scrollView.frame.size.width; int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1; pageControl.currentPage = page; // load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling) [self loadScrollViewWithPage:page - 1]; [self loadScrollViewWithPage:page]; [self loadScrollViewWithPage:page + 1]; // A possible optimization would be to unload the views+controllers which are no longer visible } // At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { pageControlUsed = NO; } - (IBAction)changePage:(id)sender { int page = pageControl.currentPage; // load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling) [self loadScrollViewWithPage:page - 1]; [self loadScrollViewWithPage:page]; [self loadScrollViewWithPage:page + 1]; // update the scroll view to the appropriate page CGRect frame = scrollView.frame; frame.origin.x = frame.size.width * page; frame.origin.y = 0; [scrollView scrollRectToVisible:frame animated:YES]; // Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above. pageControlUsed = YES; } @end </code></pre> <p><strong>MyViewController.h</strong></p> <pre><code>#import &lt;UIKit/UIKit.h&gt; @interface MyViewController : UIViewController { UILabel *pageNumberLabel; int pageNumber; } @property (nonatomic, retain) IBOutlet UILabel *pageNumberLabel; - (id)initWithPageNumber:(int)page initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; @end </code></pre> <p><strong>MyViewController.m</strong></p> <pre><code>#import "MyViewController.h" @implementation MyViewController @synthesize pageNumberLabel; - (void)loadView { } - (void)viewDidLoad { [super viewDidLoad]; // Set the label and background color when the view has finished loading pageNumberLabel.text = [NSString stringWithFormat:@"Page %d", pageNumber + 1]; } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return (interfaceOrientation == UIInterfaceOrientationPortrait); } // Load the view nib and initialize the pageNumber ivar // classic initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil // class adapted to init the page number // /!\ be careful, I'm not sure it's working properly - (id)initWithPageNumber:(int)page initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { pageNumber = page; NSLog(@"pageNumber = %i", pageNumber); } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } @end </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload