I have a view controller implementing UIPageViewControllerDataSource delegate, and it contains a UIPageViewController.
My issue is that, after 3 hours of tutorials and reading, I still don't understand why the UIPageController reacts to swipe by moving it's content, but it doesn't change the page if the scroll is enough. It's always stuck on the first page.
So this is my .h file
#import <UIKit/UIKit.h>
#interface BreathePageViewController : UIViewController <UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageController;
#end
And this is my .m file
#import "BreathePageViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h.h"
#interface BreathePageViewController () {
NSArray *pageViewControllerScreens;
FirstViewController *firstViewController;
SecondViewController *secondViewController;
int pageIndex;
}
#end
#implementation BreathePageViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
pageIndex = 0;
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self view] bounds]];
[self.pageController setViewControllers:#[firstViewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
[self.view addSubview:self.pageController.view];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
if (pageIndex == 0) {
return nil;
}
pageIndex--;
return [self viewControllerAtIndex:pageIndex];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
if (pageIndex == 2) {
return nil;
}
pageIndex++;
return [self viewControllerAtIndex:pageIndex];
}
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index {
UIViewController *vc;
if (pageIndex == 0 ) {
vc = [[FirstViewController alloc] init];
}
else if (pageIndex == 1) {
vc = [[SecondViewController alloc] init];
}
return vc;
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
return 2;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
return 0;
}
#end
Now the strange stuff is that the pageViewController:viewControllerAfterViewController is never called.
Can someone help me out?
Thank you
After a night of sleep, I am going to to reply my own question.
I don't know why (any comment appreciated), but the problem was not on that view controller, but it was in the one I was creating it in.
In the parent view controller I was building the UIPageViewController like that:
BreathePageViewController *pageController = [[BreathePageViewController alloc] init];
[pageController.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:pageController.view];
And now I tried to move the declaration of pageViewController as an iVar. And it works.
Hope to help someone else
Related
I have a UIViewController which has a UIPageViewController property. The problem I am running into is when a viewcontroller is dragging (uitableview/uitableviewcell), the pageviewcontroller swipe takes over and changes the page when scrolling in its childrencontroller view.
I tried adding a gesture and checking if the touch is a UITableViewCell to prevent gesture touch but its not working.
I am trying to achieve similar feel that twitter or snapchat app have when you swipe left to right a new viewcontroller view is shown.
#import "ContainerViewController.h"
#interface ContainerViewController () <UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIGestureRecognizerDelegate>
#property (nonatomic, strong) UIPageViewController *pageViewController;
#end
#implementation ContainerViewController
- (id)initWithViewControllers:(NSArray *)viewControllers
{
self = [super init];
if (self) {
self.viewControllers = viewControllers;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:self.pageViewController.view];
}
#pragma mark - Accessors
- (UIPageViewController *)pageViewController
{
if (_pageViewController) {
return _pageViewController;
}
_pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.0f] forKey:UIPageViewControllerOptionInterPageSpacingKey]];
_pageViewController.dataSource = self;
_pageViewController.delegate = self;
for (UIView *view in _pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
UIPanGestureRecognizer *g = [[UIPanGestureRecognizer alloc] initWithTarget:self action:nil];
g.delegate = self;
UIScrollView *scrollView = (UIScrollView *)view;
[scrollView addGestureRecognizer:g];
}
}
[_pageViewController setViewControllers:#[self.viewControllers[1]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
return _pageViewController;
}
#pragma mark - UIPageViewControllerDataSource
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [self.viewControllers indexOfObject:viewController];
if (index == 0) {
return nil;
}
return self.viewControllers[index - 1];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self.viewControllers indexOfObject:viewController];
if (index >= self.viewControllers.count - 1) {
return nil;
}
return self.viewControllers[index + 1];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
// UITableViewCellContentView => UITableViewCellScrollView => UITableViewCell
if([touch.view.superview.superview isKindOfClass:[UITableViewCell class]]) {
NSLog(#"PREVENT SCROLLL");
return NO;
}
return YES;
}
#end
I am new to iOS development, and I am having some issues showing images in a simple page view controller photo gallery.
The problem I am having is that the images in the child view won't be displayed. The only thing showing is a blank page.
Here is the view controller file holding page view controller:
#import "RTPGalleryViewController.h"
#import "RTPSinglePhotoViewController.h"
#import "JMImageCache.h"
#interface RTPGalleryViewController ()
#end
#implementation RTPGalleryViewController
#synthesize photosArray, pageViewController, pagesArray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
pagesArray = [[NSMutableArray alloc] init];
[self generatePhotoViews];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.dataSource = self;
[[self.pageViewController view] setFrame:[[self view] bounds]];
RTPSinglePhotoViewController *initialViewController = [pagesArray objectAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[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 - 30);
[self addChildViewController:self.pageViewController];
[[self view] addSubview:[self.pageViewController view]];
[self.pageViewController didMoveToParentViewController:self];
// Do any additional setup after loading the view.
}
-(void) initWithPhotoArray:(NSMutableArray *) photos{
self.photosArray = photos;
}
-(void) generatePhotoViews{
for (int i=0; i< [photosArray count]; i++) {
RTPSinglePhotoViewController *view = [[RTPSinglePhotoViewController alloc] init] ;
view.imageUrl = [photosArray objectAtIndex:i];
view.pageIndex = i;
[pagesArray addObject:view];
}
}
- (RTPSinglePhotoViewController *)viewControllerAtIndex:(NSUInteger)index
{
NSLog(#"PHOTO ARRAY COUNT IS: %lu", (unsigned long)[photosArray count]);
if ([self.pagesArray count] == 0) {
return nil;
}
return [pagesArray objectAtIndex:index];
;
}
#pragma mark - Page View Controller Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = ((RTPSinglePhotoViewController*) viewController).pageIndex;
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
NSLog(#"THE INDEX NOW IS %lu",(unsigned long)index);
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = ((RTPSinglePhotoViewController*) viewController).pageIndex;
if (index == ([pagesArray count]-1) || index == NSNotFound) {
return nil;
}
NSLog(#"THE INDEX NOW IS %lu",(unsigned long)index);
index++;
return [self viewControllerAtIndex:index];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
return [self.photosArray count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
return 0;
}
#end
RTPSinglePhotoViewController is the content view controller holding images here is the code:
#import "RTPSinglePhotoViewController.h"
#import "JMImageCache.h"
#interface RTPSinglePhotoViewController ()
#end
#implementation RTPSinglePhotoViewController
#synthesize imageView,imageUrl;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString * path = imageUrl;
NSURL * url = [NSURL URLWithString:path];
// [cell.thumbnailImageView setImageWithURL:url key:nil placeholder:nil completionBlock:nil failureBlock:nil];
[[JMImageCache sharedCache] imageForURL:url completionBlock:^(UIImage *downloadedImage) {
imageView.image = downloadedImage;
} failureBlock:nil];
// Do any additional setup after loading the view.
}
#end
Now, according to the log, the image is being downloaded/cached properly, it is just not showing up. Seeing a blank page instead of photo. What am I doing wrong?
Any suggestions would be appreciated!
I suppose you are not using storyboard.
The way you are allocating view controllers is:
RTPSinglePhotoViewController *view = [[RTPSinglePhotoViewController alloc] init] ;
Where it should be:
RTPSinglePhotoViewController *view = [[RTPSinglePhotoViewController alloc] initWithNibName:#"The name of the xib associated with this controller" bundle: [NSBundle mainBundle]];
The problem is that you are not associating any view to your view controller, therefore nothing is displayed
EDIT: Since you're using storyboards the right way to instantiate the view controller is:
RTPSinglePhotoViewController *view = (RTPSinglePhotoViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"your_controllers_storyboard_id"];
I have three view controllers: Settings,Chatbox and QuickMsg.
I want to use UIPageViewController to switch between these three view controllers. For each view controller, I don't want to re-initiate the view controller between swiping pages since it contains user inputed data and I want to persist the data. I defined three view controllers as static variables.
The screen goes black when I swipe between pages. Where have I done wrong?
Thanks a lot in advance!
ChatboxController, SettingController and QuickMsgController are three UIViewController controllers.
PagingViewController.h
#import <UIKit/UIKit.h>
#import "ChatboxController.h"
#import "SettingController.h"
#import "PagingViewController.h"
#import "QuickMsgController.h"
#class ChatboxController;
#class SettingController;
#class QuickMsgController;
#interface PagingViewController : UIViewController<UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageController;
#property (assign, nonatomic) NSInteger index;
+(ChatboxController*) getChatboxController;
+(SettingController*) getSettingsController;
#end
PagingViewController.m
#import "PagingViewController.h"
#interface PagingViewController ()
#end
#implementation PagingViewController
static ChatboxController* chatboxViewController;
static SettingController* settingViewController;
static QuickMsgController* quickMessageViewController;
int defaultIndex=1;
NSArray *viewControllers;
+(ChatboxController*) getChatboxController
{
return chatboxViewController;
}
+(SettingController*) getSettingsController
{
return settingViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
self.index--;
if(self.index<0)
{
self.index=0;
}
return [self viewControllerAtIndex:self.index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
self.index++;
return [self viewControllerAtIndex:self.index];
}
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index {
NSLog(#"index:%d",index);
if(index==1)
{
return chatboxViewController;
}
else if (index==0){
return settingViewController;
}else if(index==2)
{
NSLog(#"Quick Message");
return quickMessageViewController;
}else{
NSLog(#"error here");
return nil;
}
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
// The number of items reflected in the page indicator.
return 3;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
// The selected item reflected in the page indicator.
return defaultIndex;
}
- (void)viewDidLoad
{
[super viewDidLoad];
chatboxViewController= [self.storyboard instantiateViewControllerWithIdentifier:#"chatbox"];
settingViewController= [self.storyboard instantiateViewControllerWithIdentifier:#"settings"];
quickMessageViewController=[self.storyboard instantiateViewControllerWithIdentifier:#"quickmessages"];
self.index=defaultIndex;
// [self performSelector:#selector(loadingNextView) withObject:nil afterDelay:2.0f];
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self view] bounds]];
NSArray *viewControllers = [NSArray arrayWithObject:chatboxViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Put your content view controllers in an NSArray:
#property (nonatomic, strong) NSArray *contentViewControllers;
Use:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [self.contentViewControllers indexOfObject:viewController];
if (index == 0) {
return nil;
}
return self.contentViewControllers[index - 1];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [self.contentViewControllers indexOfObject:viewController];
if (index >= self.contentViewControllers.count - 1) {
return nil;
}
return self.contentViewControllers[index + 1];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
return self.contentViewControllers.count;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
return 0;
}
I've used a tutorial on AppCoda for adding a sort of tutorial style UIPageViewController - it works amazingly - it's just that I can't remove it on a button click.
Here's my PageViewController:
#import "startupViewController.h"
#import "SKSlideViewController.h"
#import "APPChildViewController.h"
#interface startupViewController ()
#end
#implementation startupViewController
#synthesize outletWallpaper;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self mymethod];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)mymethod {
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self view] bounds]];
APPChildViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
}
- (APPChildViewController *)viewControllerAtIndex:(NSUInteger)index {
APPChildViewController *childViewController = [[APPChildViewController alloc] initWithNibName:#"APPChildViewController" bundle:nil];
childViewController.index = index;
return childViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(APPChildViewController *)viewController index];
if (index == 0) {
return nil;
}
// Decrease the index by 1 to return
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(APPChildViewController *)viewController index];
index++;
if (index == 3) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
// The number of items reflected in the page indicator.
return 3;
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
// The selected item reflected in the page indicator.
return 0;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(#"Switching View Controllers...");
SKSlideViewController *slideController=(SKSlideViewController *)[segue destinationViewController];
[slideController setStoryBoardIDForMainController:#"MainVC" leftController:#"LeftVC" rightController:#"RightVC"];
[slideController reloadControllers];
}
#end
This code sends me to another file which from there, I need to remove the whole thing.
I think I did the same tutorial on appcoda, and had the same question!
A solution that has worked for me I stumbled across accidentally on another question:
// Replace deleteVC with your UIPageViewController
[deleteVC willMoveToParentViewController:nil];
[deleteVC.view removeFromSuperview];
[deleteVC removeFromParentViewController];
var movingIndex = 0
var forwardDirection = false
if selectedIndex == images.count{ //ur pages dataSource You may not need this
movingIndex = selectedIndex - 1
forwardDirection = false
} else {
movingIndex = selectedIndex
forwardDirection = true
}
controllers.remove(at: selectedIndex)
capturedInspectionPhotoView.imagePageController?.dataSource = self
capturedInspectionPhotoView.imagePageController?.setViewControllers([controllers[movingIndex]],
direction: forwardDirection ? .forward : .reverse, animated: true)
I took the Photo Scroller example from Apple's website and tried to implement my own Album by copying the code. Now, the UIScrollView is not visible. How do I make it appear?
The only code change that I made was in creating the UIPageViewController. In my case, it's a UIViewController that is opening it and not the AppDelegate.
#implementation BasePhotoViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nil bundle:nibBundleOrNil];
if (self) {
// kick things off by making the first page
PhotoViewController *pageZero = [PhotoViewController photoViewControllerForPageIndex:0];
if (pageZero != nil)
{
// assign the first page to the pageViewController (our rootViewController)
//UIPageViewController *pageViewController = (UIPageViewController *) [[UIApplication sharedApplication] keyWindow].rootViewController;
UIPageViewController *pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:0 navigationOrientation:0 options:nil];
//UIPageViewController *pageViewController = (UIPageViewController *)self.parentViewController;
pageViewController.dataSource = self;
[pageViewController setViewControllers:#[pageZero]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
}
}
return self;
}
You are not adding the pageViewController's view as a subview of BasePhotoViewController's view. Your BasePhotoViewController class should look something like this. Note the code in viewDidLoad.
BasePhotoViewController.h:
#interface BasePhotoViewController : UIViewController <UIPageViewControllerDataSource>
#property (nonatomic, strong) UIPageViewController * pageViewController;
#end
BasePhotoViewController.m:
#import "BasePhotoViewController.h"
#import "PhotoViewController.h"
#implementation BasePhotoViewController
#synthesize pageViewController;
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
PhotoViewController *pageZero = [PhotoViewController photoViewControllerForPageIndex:0];
if (pageZero != nil)
{
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:0
navigationOrientation:0
options:nil];
self.pageViewController.dataSource = self;
[self.pageViewController setViewControllers:#[pageZero]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
}
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
}
# pragma mark - UIPageViewControllerDataSource
- (UIViewController *)pageViewController:(UIPageViewController *)pvc viewControllerBeforeViewController:(PhotoViewController *)vc
{
NSUInteger index = vc.pageIndex;
return [PhotoViewController photoViewControllerForPageIndex:(index - 1)];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pvc viewControllerAfterViewController:(PhotoViewController *)vc
{
NSUInteger index = vc.pageIndex;
return [PhotoViewController photoViewControllerForPageIndex:(index + 1)];
}
#end
Note: I've initialised the UIPageViewController in initWithCoder: because Apple's Photo Scroller code uses a storyboard. I removed the UIPageViewController from the storyboard and created a BasePhotoViewController in its place. If you are not loading BasePhotoViewController from a storyboard, you should move the code in initWithCoder: to the appropriate initialiser.
EDIT: See this sample project on github.