UIViewController inside another UIViewController, is it possible? - ios

I'm making a newsstand app and I need multiple components in a single view. I have a UIViewController that displays and manages a pdf (zooming, scrolling,etc...) but I don't want it to be full screen instead I want it to be like an UIView inside another UIViewController which has a menu on top, page numbering on the bottom and other tools. Both are subclass of UIViewController... I already have both working separately. I just want the pdf viewer inside the other. Is it possible? here's some code of what I want (lets say is inside the viewDidLoad)... but obviously doesn't work. Any help is appreciated. It also must be IOS 5.1.1 compatible and above
NSString *path = [[NSBundle mainBundle] pathForResource:#"myPdf" ofType:#"pdf"];
PDFViewController *page = [[PDFViewController alloc] initWithPDFAtPath:path];
//pdfView is a UIView of size 600x600 right in the middle
[self setPdfView:[page view]]; //this doest work... but it's basically what I want instead of presenting a viewController
//[self presentViewController:page animated:YES completion:NULL];
I'm also aware of this, but I don't understand... if this is the way I would like some guidance:
addChildViewController:
willMoveToParentViewController:
didMoveToParentViewController:

As of iOS 5 you can do View Controller Containment which lets you add child view controllers into a parent view controller. The child view controllers can manage all the logic like they normally would but the view of the child controller can match any frame/position you like.
To add the controller you can do
[self addChildViewController:childViewController];
childViewController.view.frame = [self frameForChildController];
[self.view addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];
You can learn more about it in the View Controller Documentation

Related

Create instance of a UIView - iOS

I am designing an iOS app with 10 main UIViewControllers in it. Each representing a different section of the app. Its basically for a company and shows info about the company.
One of the things I am doing on bottom section of the app (in all the different view controllers) is displaying a UIView which contains a map. This map shows a certain location.
Now it works, but the problem I have is that I have 10 copies of the same code and 10 copies of the same UIView.
Is there anyway I could make a small view controller with one class attached to it that would handle the map and then just create an instance of the view controller in all my 10 view controllers in my app?
I hope my question makes sense. Basically I want to know how I can go about reusing ONE UIView in all 10 of my ViewControllers. So I can just call it or something and it appears.
Update - this is basically what I am trying to achieve
Thanks, Dan.
View controllers can contain other view controllers. You can either use a container view in a storyboard or setup the relationship programmatically (see: Creating Custom Container View Controllers).
The storyboard container view is easiest, but the programmatic solution isn't too bad.
- (void)displayContentController:(UIViewController *)content
{
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
// NOTE: You could also add it to any subview of self.view.
[self.view addSubview:content.view];
[content didMoveToParentViewController:self];
}
- (CGRect)frameForContentController
{
return CGRectMake(…);
}
- (void)viewDidLoad
{
…
MyMapViewController *mapViewController = …;
[self displayContentController:mapViewController];
…
}
- (void)dismissContentController:(UIViewController *)content
{
[content willMoveToParentViewController:nil];
[content.view removeFromSuperview];
[content removeFromParentViewController];
}
Final Note: Have each parent view create its own instance of the map view controller. Resist the temptation to reuse an instance of the map view controller between parents.
Update to address questions
So lets say I had 2 of the same view controllers open at once and they both were displaying the same imported viewcontroller then it wouldn't work right?
You can't do this. An instance of a view controller can only have 1 parent view controller. Create separate instances for each use.
So if I create different instances, I can reuse the same view lets say 5 times in one view?
Yes, if you create different instances, you can put as many as you need on a view.
Let me be clear, an instance is a distinct memory location created using a constructor.
MyMapViewController *mapViewController1 = [[MyMapViewController alloc] initWithNibName:#"MyMapViewController" bundle:nil];
MyMapViewController *mapViewController2 = [[MyMapViewController alloc] initWithNibName:#"MyMapViewController" bundle:nil];
or
MyMapViewController *mapViewController1 = [self.storyboard instantiateViewControllerWithIdentifier:#"MapViewController"];
MyMapViewController *mapViewController2 = [self.storyboard instantiateViewControllerWithIdentifier:#"MapViewController"];
Updated to demonstrate dismissing a container view controller.
Here is a method for a child view controller, so it can use to dismiss itself.
- (void)dismissFromParentViewController
{
[self willMoveToParentViewController:nil];
[self.view removeFromSuperview];
[self removeFromParentViewController];
}
Please try below method:
Create "map controller" super class with inherit to UIViewController and define your need common method and variables.
Inherit your 10 child class into "map controller" super class. And connect common IBOutlets and IBActions to super class.
You can access common methods and variable to super class from child class(10 view controller child class).
Please refer below code
#interface mapController : UIViewController
{
NSString *mapControllerVariables;
}
-(IBAction)mapControllerActions:(id)sender;
#end
#interface yourChileView : mapController
{
}
#end

Remove viewcontroller & move to next view controller

Hi i have been working on an iOS app.What i am doing is navigating among diffrent view controllers. But the problem is i want finish the current view controller from emoery and then move to the next view controller.
I am using `[self.view removeFromSuperview]; for finishing the cureent view & using
self.loginView = [self.storyboard instantiateViewControllerWithIdentifier:#"LOGIN"];
[self presentViewController:self.loginView animated:NO completion:nil];
for moving to next view controller but the thing is i am not able to remove it from memory.
Please tell me how can i do it?
Thanks in advance.
`
It's better to create a container view controller which manages your view controllers. For example, in viewDidLoad: of container controller you add current controller:
[self addChildViewController:self.currentViewController];
[self.currentViewController didMoveToParentViewController:self];
[self.view addSubView:self.currentViewController.view];
//here set up currentViewController view's frame or constraints if needed
When you need to open login controller, do this:
[self addChildViewController:loginViewController];
[self.loginViewController didMoveToParentViewController:self];
[self.view addSubView:loginViewController.view];
//here set up loginViewController view's frame or constraints if needed
//then remove current view controller
[self.currentViewController willMoveToParentViewController:nil];
[self.currentViewController removeFromParentViewController];
[self.currentViewController.view removeFromSuperview];
Remove from superview will remove it from the current view, but OS won't remove it until he needs to (this is topic for more explanation, let's say it won't remove it asap).
If you want something deleted just call it nil:
self.view = nil;
This will make the pointer to nil, so view won't be there any more. (the view really will be somewhere but you won't have access to it)
I am revising your code
self.loginView = [self.storyboard instantiateViewControllerWithIdentifier:#"LOGIN"];
[self presentViewController:self.loginView animated:NO completion:nil];
What you are doing here is presenting your login viewcontroller.
self: This is the instance of the viewcontroller you are currently working on. So how could you remove self from memory. (Not Possible)
You can approach alternate ways.
For example: 1. Changing root view controller
Pop to root view controller and then Push Login View controller.
If you try to remove not only UIView but the whole UIViewController from a navigation controller stack use this snippet
NSMutableArray *stack = [[NSMutableArray alloc] initWithArray: self.navigationController.viewControllers];
[stack removeObject:yourController];
self.navigationController.viewControllers = stack;
Be aware of using this only when you've already pass to the next controller view.
UPD:
Oh, now I see what you are trying to do. And I can't figure out, why you're trying to step your controllers this way (modally). I think you should use UINavigationController with navigation segues defined directly from your storyboard. Look at this article where apple purely explains what navigation is. That article is about modal views

UIViewController on top of UINavigationBar

I am trying to add custom UIViewController on top of everything but not covering full screen (basically popover), like this:
- (void) displayPopoverController: (UIViewController*) content;
{
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:content.view];
[content didMoveToParentViewController:self];
}
Everything works, but unfortunately it is underneath the navigation bar. So I decided to add UIViewController to the navigation controller like this:
- (void) displayPopoverController: (UIViewController*) content;
{
[self.navigationController addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.navigationController.view addSubview:content.view];
[content didMoveToParentViewController:self.navigationController];
}
It worked, but there are 2 problems:
1) viewWillAppear is not called when I add popover (only viewDidLoad is called)
2) If I change orientation, my popover receives notification and adjusts to new orientation, but UIViewController behind it does not. It will only update its view after I remove popover.
Is there any way to fix 1 and 2? Maybe there is better approach(I don't want to use UIPopoverController with custom UIPopoverBackgroundView)?
IMO you should make a custom transition and present UIViewController modally.
You can get help on Custom UIViewController transition here : http://www.doubleencore.com/2013/09/ios-7-custom-transitions/
I am trying to add custom UIViewController on top of everything but not covering full screen
If you can confine yourself to iOS 7, your problems are over. You can use presentViewController: and a custom transition to do exactly what you are trying to do. This, in my view, is the most important new feature of iOS 7: you can present a view controller's view only partially covering the main interface.
See my book; for the particular example code from the book, see https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch06p304customPresentedAnimation2/ch19p620customPresentedAnimation2/ViewController2.m
Plus I've now posted a single project at https://github.com/mattneub/custom-alert-view-iOS7. It shows how to make a view controller presented view that only partially covers the interface, plus it demonstrates that device rotation works correctly for all visible views (i.e. what's in front and what's visible behind).

My viewController doesn't show up right

in my iPad-app I am trying to present one of my views with a modal formsheet-style.
Here's some code:
-(void)present
{
SecondViewController *modal = [[SecondViewController alloc]init];
modal.modalPresentationStyle = UIModalPresentationStyleFormSheet;
[self presentModalViewController:modal animated:YES];
}
I am using Storyboard, and I have put stuff like a textView and toolbars in the view I'd like to show. I have set the right class in Identity Inspector, and in the class-files I have checked that it's the right view appearing with putting NSLog(#"Right view");
When calling the void present, a view is appearing, but only as a dark-white square. Nothing og my content from Storyboard is in it, I even tried changing the background color of the view and the textView to see if something was just outside the square, but the whole thing stayed white. It feels like it's not using the view I created in storyboard, but I have set it to the correct class, and the NSLog gets printed out when calling it. I have not connected the two views in any way in Storyboard, the SecondViewController is just floating around, so that might be the problem? The button that calls for -(void)present is created programmatically, so I can't ctrl+drag it to the button either.
Why is it showing an empty version of my class?
In the "Identity Inspector" set a "Storyboard ID" for your ViewController, and then present it like this:
-(void)present
{
SecondViewController *modal = [self.storyboard instantiateViewControllerWithIdentifier:#"myStoryboardID"];
modal.modalPresentationStyle = UIModalPresentationStyleFormSheet;
[self presentModalViewController:modal animated:YES];
}
And if you're using iOS6, presentModalViewController:animated: is deprecated, so use this:
-(void)present
{
SecondViewController *modal = [self.storyboard instantiateViewControllerWithIdentifier:#"myStoryboardID"];
modal.modalPresentationStyle = UIModalPresentationStyleFormSheet;
[self presentViewController:modal animated:YES completion:nil];
}
Your problem is that you're assuming the program will intrinsically know where to find the, already laid out, view for this controller when that's simply not how storyboards work. The code you list about will create a view controller, but without an associated view it will simply show as a black square.
There's a few ways to solve your dilemma:
Add the modal transition as a segue in the view controller, this would be the simplest way and is what iOS storyboards expect you to do.
Move the view from the storyboard to an external .xib and call the initWithNibName:bundle: method to load this as your view controller's view. This is the best solution if you just want to programmatically load the view.
Load the view from your storyboard programmatically with the instantiateViewControllerWithIdentifier: method, this is probably a bad idea as it goes against the design of storyboards.
I can elaborate on those if you want.

iOS uiview and uiviewcontroller

Hy
i have two classes uiviewcontroller and uiview. I have one view controller. Inside i have uiview. Inside uiview i have textfield and when i write a text and click done i need to refresh uiviewcontroller.
I tried with this in uiview class:
-(IBAction)textFieldReturn:(id)sender
{
ViewController *vc = [[ViewController alloc] init];
[vc viewDidLoad];
}
i need refresh the same as you click the button and open viewcontroller.
I am guessing you mean that you want to "refresh" the view, not the view controller. To do that simply call [self setNeedsDisplay] from the view, or [self.view setNeedsDisplay] from the view controller. Also make sure that the textfield is a subview of the uiview. Either do that in the nib file or in code by calling [self addSubview: (textfield here)].
Also, if you want to access the view controller from the view you will need to create an IBOutlet, simply allocating a new ViewController object within the view does not mean that the created view controller controls the view. Hopefully that makes sense. I'd recommend going through some ios starter tutorials as well. Just google that there are a lot.

Resources