I am trying to use UIPageViewController to create walkthrough screens with three separate UIViewControllers. As a summary, I have four View Controllers and a Page View Controller in my storyboard. One view controller act as base view (XYZViewController.h/m) and other three act as sub views that loads inside base view controller. Below shows how the XYZViewController.h displays roughly.
#import <UIKit/UIKit.h>
#import “XYZPageContentViewController.h"
#import "XYZPageTwoContentViewController.h"
#import "XYZPageThreeContentViewController.h"
#interface XYZViewController : UIViewController <UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageViewController;
#end
Following code snippet shows the viewDidLoad method of XYZViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
XYZPageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height - 60);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
bottomView.layer.zPosition = 1;
startBtnOutlet.layer.zPosition = 1;
}
Actually, loading sub views and walkthrough is working perfectly. What is not working is, the button touch up inside event I have declared in base view.
As you can see with the image, there is "Start again" button at the bottom of the screen. At first that view even didn't display when I set page controller view till bottom of the screen and not using z-index option.
Which means having this line
self.pageViewController.view.frame = CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height - 60);
with commenting following lines.
// bottomView.layer.zPosition = 1;
// startBtnOutlet.layer.zPosition = 1;
What I need is limit the page view controller where the gray view begins and available the sub view till end of the screen. I can limit the page view controller frame as mentioned above, then it is apply to my all walkthrough screens as well. What can I do for that?
I have followed this tutorial. Is there any better way to do this?
Found the solution.
Keep comment below lines of codes.
// bottomView.layer.zPosition = 1;
// startBtnOutlet.layer.zPosition = 1;
Add this line below that code, inside viewDidLoad method
[self.view sendSubviewToBack:_pageViewController.view];
Related
I have successfully created a "tutorial" pages that will show up at the first time user open the app. And i am facing the problem on how to move to another "branch" of view controllers in my storyboard.
So basically I have two main flows in my storyboard:
1. Page View Controllers
2. Main app view controllers
As you can see from screenshot below
So, the question is, how to move to my main app flow after the user clicked on the skip button from my UIPageViewController?
In my tutorial page view controller, i have this code to set the page view controllers
- (void)viewDidLoad {
[super viewDidLoad];
self.arrPageTitles = #[#"A",#"B",#"C"];
self.arrPageImages =#[#"1.jpg",#"2.jpg",#"3.jpg"];
// Create page view controller
self.PageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"pageViewController"];
self.PageViewController.dataSource = self;
TutorialPageContentViewController *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 - 30);
[self addChildViewController:self.PageViewController];
[self.view addSubview:self.PageViewController.view];
[self.PageViewController didMoveToParentViewController:self];
}
Or is there any better approach to achieve this? Is my design wrong?
I have searching for any clue but can't find any. Thanks!
First of all I'd recommend you to use different storyboards for Tutorial flow and for main app screens. It's very hard to store everything in single storyboard: you will get some mess when project will have at least 20-30 view controllers.
And you can replace root view controller at any time using this code:
let storyboard = UIStoryboard(name: "<storyboard_name>", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "<vc_name>")
UIApplication.shared.keyWindow?.rootViewController = viewController
I need advice to create user interface like this UI.
Is it better to use UITableView or UICollectionView because its display is row based? But, when I swipe left and right, it has different section like the collection view horizontal scroll. It makes me confused because I have never created such a UI. I prefer to use UITableViewController, but when I see the segment, I can't use segmented controller because I can't swipe to change the filter.
1) Create storyboard view controller (UIViewController). Controller's view has two subviews: title view and container view (two IBOutlet views).
2) Title view - it's a top view (in your case - collection view with items).
Container view - it's a view for pageViewController.
You will do something like this:
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:nil];
self.pageViewController.dataSource = self;
self.pageViewController.delegate = self;
[self.pageViewController setViewControllers:#[[self viewControllerForIndex:index]]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
[self addChildViewController:self.pageViewController];
[self.containerView addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
- (UIViewController *)viewControllerForIndex:(NSUInteger)index {
UITableViewController *vc = [[UITableViewController alloc] init];
return vc;
}
before asking this question, I did some research of course. One of the links or topics I have found on google and on stackoverflow is this:
How do I load another view controller from the current view controller's implementation file?
In my case, I have two viewcontrollers in my project, namely:
ViewController (ViewController.h and ViewController.m) - my main vc
LeftViewController (LeftViewController.h and LeftViewController.m) - my second vc. It will be loaded upon clicking a button from my main vc.
Please take note that it is my 3rd day in my job, self training, and I find objective-c quite hard compared to others, like C# ... Oh I miss C#.
Going on, I tried following the steps from the links that I've got as well as the link I gave at the top.
Here are my codes:
a. Inside my ViewDidLoad in my ViewController.m
// add navigation button left
UIButton *leftNavigationButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[leftNavigationButton setFrame:CGRectMake(10, 65, 30, 20)];
[leftNavigationButton setTitle:#"<" forState:UIControlStateNormal];
[leftNavigationButton addTarget:self action:#selector(navigateLeft) forControlEvents:UIControlEventTouchUpInside];
[leftNavigationButton.layer setBorderWidth:1.0f];
[leftNavigationButton.layer setBorderColor:[[UIColor whiteColor] CGColor]];
[leftNavigationButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.view addSubview:leftNavigationButton];
b. the method inside my ViewController.m (of course outside the ViewDidLoad:
- (void)navigateLeft
{
// LeftViewController *leftViewController = [[LeftViewController alloc] init];
// [leftViewController viewDidLoad];
_leftViewController = [[LeftViewController alloc] initWithNibName:#"UI For LeftButton" bundle:nil];
[self.ViewController: self.leftViewController animated:YES completion:nil]; //Error in this line, spefically in self.ViewController<---
}
c. ViewController.h
//
// ViewController.h
// Navigation_Task
//
// Created by Glenn on 9/4/15.
// Copyright (c) 2015 Ayi. All rights reserved.
//
#import <UIKit/UIKit.h>
// for LeftViewController
#class LeftViewController;
#interface ViewController : UIViewController
#property (nonatomic, retain) NSMutableString *resultText;
// for LeftViewController
#property (strong, nonatomic)LeftViewController *leftViewController;
#end
and lastly, (this is not included in the link above), my code for loading the LeftViewController.
a. viewDidLoad in LeftViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
LeftViewController *leftViewController = [[LeftViewController alloc] initWithNibName:nil bundle:nil];
// set background and title of the view
[leftViewController.view setBackgroundColor:RGB(19,181,234)];
leftViewController.title = #"Left View Controller";
[self.navigationController pushViewController:leftViewController animated:YES];
}
Sorry if this question is too long, I can't shoot my questions to the developers here in the office, because I'm shy and they don't wanna be bothered :(
You are using right Controller for navigation i.e. UINavigationController, but to make it navigate I will recommend you to use storyboards. Take your UINavigationController as a rootviewcontroller and further take any UIViewController as its rootviewcontroller and then on 2nd UIViewController to navigate attach a Segue to it and provide it a identifier let say "PushToSecond" and in your buttons Method do the following:
(void)navigateLeft
{
[self performSegueWithIdentifier:#"PushToSecond" sender:self];
}
hope this would help
I suggest you take a look into Apple's documentation on UINavigation.
documentation
You can either add as many viewController objects into the navigation stack as needed or present it incase you need to show it temporarily.
I would like to answer my own question.
I have two buttons in my main ViewController.
1 button for LeftViewController
1 button for RightViewController.
Meaning I need to display each new viewcontroller or screen when I click 1 of those buttons.
Here are my codes:
Just inside the event handler (is my term correct? I'm from windows) of the two buttons, put the following:
Code for 'Left Screen/View Controller'
- (void)navigateLeft
{
// LeftViewController *leftViewController = [[LeftViewController alloc] init];
// [leftViewController viewDidLoad];
// _leftViewController = [[LeftViewController alloc] initWithNibName:#"UI For LeftButton" bundle:nil];
LeftViewController *leftViewController = [[LeftViewController alloc] initWithNibName:nil bundle:nil];
// set background and title of the view
[leftViewController.view setBackgroundColor:RGB(19,181,234)];
leftViewController.title = #"Left View Controller";
[self.navigationController pushViewController:leftViewController animated:YES];}
Similarly, I need to put the same type of codes (just renaming the leftViewController into RightViewController)
- (void)navigateRight
{
RightViewController *rightViewController = [[RightViewController alloc] initWithNibName:nil bundle:nil];
// set background and title of the view
[rightViewController.view setBackgroundColor:RGB(19,181,234)];
rightViewController.title = #"Right View Controller";
[self.navigationController pushViewController:rightViewController animated:YES];
}
Now I can push any of the two button and will display a new ViewController (or screen).
I don't know if this is the right key to search "add UIViewController in subview".
As what you can see in my image ,there are two ViewController, the main and the second controller. Inside the main controller there is a UIView(blue background color). Inside in UIView, I want to add the second ViewController in my UIView. I have this code but It didn't work.
here's my code
#import "ViewController.h"
#import "SampleViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIView *testView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
SampleViewController * sample = [[SampleViewController alloc] initWithNibName:#"SampleViewController" bundle:nil];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self.testView addSubview:sample.view];
}
#end
I want to know if this is possible? I know initWithNibName: works in xib file, I don't the exact term to search in google about this. I'm just trying to experiment something if this is possible in IOS. Hoping you understand what I'm trying to do. Hoping for your advice. Thanks in advance
here's my update
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIView *testView;
#property(strong,nonatomic) SampleViewController * samples;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIStoryboard *storyBoard = self.storyboard;
SampleViewController * sample = [storyBoard instantiateViewControllerWithIdentifier:#"SampleViewController"];
// SampleViewController * sample = [[SampleViewController alloc] //initWithNibName:#"SampleViewController" bundle:nil];
[self displayContentController:sample];
//commented the below line because it is not needed here, use it when you want to remove
//child view from parent.
//[self hideContentController:sample];
}
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.bounds = self.testView.bounds; //2
[self.testView addSubview:content.view];
[content didMoveToParentViewController:self]; // 3
}
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
I always get this error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/ace/Library/Developer/CoreSimulator/Devices/035D6DD6-B6A5-4213-9FCA-ECE06ED837EC/data/Containers/Bundle/Application/EB07DD14-A6FF-4CF5-A369-45D6DBD7C0ED/Addsubviewcontroller.app> (loaded)' with name 'SampleViewController''
I think, its looking for a nib. I didn't implement a nib here.
You should use Child containment concept, here MainViewController is a parent view controller and you want to add child view controller view as a subview on Main View Controller.
Adding and Removing a Child
//call displayContentController to add SampleViewCOntroller view to mainViewcontroller
[self displayContentController:sampleVCObject];
// write this method in MainViewController
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.bounds = testView.bounds; //2
[testView addSubview:content.view];
[content didMoveToParentViewController:self]; // 3
}
Here’s what the code does:
It calls the container’s addChildViewController: method to add the child. Calling the addChildViewController: method also calls the child’s willMoveToParentViewController: method automatically.
It accesses the child’s view property to retrieve the view and adds it to its own view hierarchy. The container sets the child’s size and position before adding the view; containers always choose where the child’s content appears. Although this example does this by explicitly setting the frame, you could also use layout constraints to determine the view’s position.
It explicitly calls the child’s didMoveToParentViewController: method to signal that the operation is complete.
//you can also write this method in MainViewController to remove the child VC you added before.
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
For more details, please refer to apple doc:
https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
Configuring a Container in Interface Builder, for those who don't want to write code.
To create a parent-child container relationship at design time, add a container view object to your storyboard scene, as shown in Figure 5-3. A container view object is a placeholder object that represents the contents of a child view controller. Use that view to size and position the child’s root view in relation to the other views in the container.
When you load a view controller with one or more container views, Interface Builder also loads the child view controllers associated with those views. The children must be instantiated at the same time as the parent so that the appropriate parent-child relationships can be created.
You can do this simply by using StoryBoards
Open storyboards and select the view controller in which your Blue view is present, open Utilities search for ContainerView and drag it into your blue view, this will automatically adds an view controller that acts as child view for your view. You can resize your container view in size inspector.
I've resolved the problem about the uiview on second uiviewcontroller.
Follow the code that I've used:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SecondViewController *sb = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:#"sb"];
sb.view.backgroundColor = [UIColor redColor];
[sb willMoveToParentViewController:self];
[self.view addSubview:sb.view];
[self addChildViewController:sb];
[sb didMoveToParentViewController:self];
I hope to help you.
Thanks a lot
SampleViewController * sample = [[SampleViewController alloc] initWithNibName:#"SampleViewController" bundle:nil];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self addChildViewController:sample];
[self.testView addSubview:sample.view];
You can add a childViewController to UIViewController since iOS5..
it is a great way to maker smaller, more reusable viewControllers, I also really like it.
you're really close, but you just need a couple more lines of code..
///
[self addChildViewController:sample];
[self.testView addSubview:sample.view]; //you already have this..
[sample didMoveToParentViewController:self];
In you viewWillDisappear: or one of the other teardown methods you'll need to clean up like this:
//we'll need another pointer to sample, make it an iVar / property..
[sample willMoveToParentViewController:nil]; // 1
[sample removeFromSuperview]; // 2
[sample removeFromParentViewController]; // 3
You can read the Apple docs on containing child viewControllers here https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
I'm tring to adding UIViewController in subview, and this work.
On UIViewController I've added 2 button, in .h file:
-(IBAction)matchButtonAction:(id)sender;
-(IBAction)closeButtonAction:(id)sender;
And in .m file:
-(IBAction)matchButtonAction:(id)sender
{
NSLog(#"matchButtonAction");
}
-(IBAction)closeButtonAction:(id)sender
{
NSLog(#"closeButtonAction");
}
but I don't see the log.
I need to add same parameter on UIViewController instantiateViewControllerWithIdentifier?
How to resolve the problem?
My UIViewController initialization is:
AlertDialogViewController *alertDialogView = (AlertDialogViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"alertDialogView"];
[alertDialogView willMoveToParentViewController:self];
[viewController.view addSubview:alertDialogView.view];
[viewController addChildViewController:alertDialogView];
[alertDialogView didMoveToParentViewController:viewController];
Since your view controller is in storyboard you should use instantiateViewControllerWithIdentifier to get the VC from storyboard.
SampleViewController * sample = [self.storyboard instantiateViewControllerWithIdentifier:#"IdOfSampleViewController"];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self.testView addSubview:sample.view];
Don't forget the add the identifier for the SampleViewController in storyboard
I've try to use this code:
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
secondViewController.view.frame = CGRectMake(0, 0, self.mySubView.bounds.size.width, self.mySubView.bounds.size.height);
[self addChildViewController:secondViewController];
[self.viewDialogSolution addSubview:secondViewController.view];
but I see only myview not the layout of secondViewController.
Ho to resolve the probleam?
Thanks a lot
let controller:SecondViewController =
self.storyboard!.instantiateViewController(withIdentifier: "secondViewController") as!
SecondViewController
controller.view.frame = self.view.bounds
controller.willMove(toParent: self)
self.view.addSubview(controller.view)
self.addChild(controller)
controller.didMove(toParent: self)
How can I create a UIPopoverController with integrated UINavigationController so I will be able to slide views inside the UIPopoverController left-right (with navigation bar).
UPDATE:
I open popup like this
- (void)showSettingsViewAtSenderForIPad:(id)sender
{
if (!settingsPopoverController_)
{
SettingsPopoverController *settings = [[SettingsPopoverController alloc] init];
settings.valuesGeneratorOptions = valuesGeneratorOptions_; // setting variables
self.settingsPopoverController_ = [[[UIPopoverController alloc] initWithContentViewController:settings] autorelease];
[settingsPopoverController_ setDelegate:self];
[settingsPopoverController_ setPopoverContentSize:CGSizeMake(320, 480)];
[settings release];
}
if (!infoPopoverController_.popoverVisible)
{
[settingsPopoverController_ presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
}
}
I created a controller which has a NSTableViewController as a root controller in UINavigationController
#interface SettingsPopoverController : UIViewController
{
ValuesGeneratorOptions *valuesGeneratorOptions;
IBOutlet SettingsViewController *settingsViewController;
IBOutlet UINavigationController *navigationController;
}
...
#implementation SettingsPopoverController
...
- (void)viewDidLoad
{
self.settingsViewController.valuesGeneratorOptions = self.valuesGeneratorOptions;
[self.view addSubview:self.navigationController.view];
[super viewDidLoad];
}
...
end
The problem is, that the table is not scrollable inside the popup. It also ignores the table style (initWithStyle not called).
Fix?
SOLUTION:
Found the solution: popOver table view
You create a new nib and a UIViewController. This nib has, as it's top level view, a plain jane UIView and a UINavigationController. The UINavigationController's top UIViewController is whatever view controller you want to display first.
You then display this nib inside your popover controller. In the view did load, you do something like this:
-(void)viewDidLoad
{
[self.view addSubview:self.navigationController.view];
}
This adds your navigation controller's view to your view in your nib, which allows it to be displayed.