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).
Related
I have the main View Controller, which is embedded in a Navigation Controller.
I want to make another view pop up and take up just the middle of the screen, so it basically looks like an action sheet. To make this view pop out, there is a button on the navigation bar (called "Unlock").
I made a new UIViewController, and gave it a new class called CustomModalViewController. Then I put a UIView inside this on the storyboard.
Am I on the right track? What should I do next? Should I embed this CustomModalViewController inside the original Navigation Controller? And perhaps then use this code somewhere:
- (void)showLoginView{
[UIView animateWithDuration:.5 animations:^{
customModalView.frame=CGRectMake(0, 225, CustomModalView.frame.frame.size.width, CustomModalView.frame.frame.size.height);
}];
}
- (void)hideLoginView{
[UIView animateWithDuration:.5 animations:^{
customModalView.frame.frame=CGRectMake(0, 480, CustomModalView.frame.frame.size.width, CustomModalView.frame.frame.size.height);
}];
}
I'm new to objective c and Xcode, and it's still weird to me how all of the files come together.
UIActionSheet disables the remaining screen. I advice you to do the same. So your way using UIViewController subclass would be an appropriate way. You should place your action buttons in the bottom of your controller's view.
You can set a semi-transparent view backgroundColor to view of the customViewController to achieve some visuality like UIActionSheet. You can easily show a modal view controller like:
[self presentViewController:customViewController animated:YES completion:^{
// do something when opened, if you need
}];
And hide like:
[self dismissViewControllerAnimated:YES completion:^{
// do something when closed, if you need
}];
As it can be seen, you don't have to deal with frames. In the manner of controlling, you can implement some delegate methods, something like CustomViewControllerDelegatein your main view controller, so you can be aware of what happened in your customViewController.
I have an iOS application using storyboards where I display a view controller that I create from an .xib file to the user. This view controller accepts some user input, but I then have to dismiss it and return to the main application. I am able to display the view controller, which also has a button that calls a method to dismiss the view controller. My problem is that after the user presses the button to go back to the main application, the entire screen goes black. Here is my code for the button from the .xib view controller that is trying to remove itself from the display:
- (IBAction)myButtonAction:(id)sender {
[self.view removeFromSuperview];
}
Here is the code from my main application's view controller which calls the .xib view Controller in the first place:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
_nextView = [[NextLandscapeViewController alloc] initWithNibName:#"NextLandscapeViewController" bundle:nil];
[_nextView setDelegate:(id)self];
NextNavigationController *navigationController = [[NextNavigationController alloc] initWithRootViewController:_nextView];
[self presentViewController:navigationController animated:YES completion:nil];
}
NextNavigationController is a subclass of UINavigationController which I do for the purpose of loading _nextView in landscape mode instead of portrait mode. This part is working fine. My concern now is dismissing this viewController after the user is finished working with it, and return back to the calling view controller in the main application.
Is there any reason why my screen is black? How I can resolve this issue?
Don't use removeFromSuperview, use [self dismissViewControllerAnimated:YES completion:nil]; Just like you use a pop to undo a push, you use dismissViewController to undo a presentViewController. The reason you get a black screen is because presenting a view controller removes the view of the presenting view controller from the window's hierarchy. So, when you remove the view from the superview, there's nothing underneath but the window.
I have a project that is a tab-bar controller. Each tab usually has a UINavigationController. The problem I have is this: I need a new tab with alot of navigation (roughly 30 navigation items grouped into 4-8 groups. Problem: My navigation bar is already full (can't use the navigation controller (or bar). What I need is navigation below the navigation bar (which has a global search bar and other global icons filling it). How can I implement this best?
What I have now: I have created a UIScrollView just under the navigation bar to serve as my "hand-rolled" navigation bar. It's a scrollView because I don't know (going forward) how many "groupings" of navigation items I will have (currently only 4). Each of these groups is represented by a UIButton, some of which should immediately present a view, and others which present a popover with further navigation items, which when selected will present a view.
Problem: I want a "content view" under my navigation view mentioned above, where I can present content based on the user's navigation choices. I have to support iOS 5.0, so I can't use the storyboard container view (unfortunately). I will have 3 types (maybe more later) of content views I will present, that I would like to create as individual view controllers and then push the appropriate one as it's selected in my navigation mentioned. Is there a 3rd party navigation controller I can use? Do I have to "roll my own"? Any advice would be greatly appreciated.
Here is a "slapped-together" picture of what I need to achieve:
I would make what you're calling the content view a subview of your main view, and use it as the view to which you will add a childViewController's view. If you haven't already read up on custom container controllers, you should do so, but the basic way of using them is like this.
The controller's whose view you show in your question would be the custom container controller. You could load up an initial controller in the viewDidLoad method, then switch the controller in your subview (I'm calling it self.containerView) in response to the user choosing something from your scroll bar:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIViewController *initial = [self.storyboard instantiateViewControllerWithIdentifier:#"InitialVC"];
[self addChildViewController:initial];
[initial.view.frame = self.containerView.bounds];
[self.containerView addSubview:initial.view];
self.currentController = initial;
}
-(void)switchToNewViewController:(UIViewController *) cont {
[self addChildViewController:cont];
cont.view.frame = self.containerView.bounds;
[self moveToNewController:cont ];
}
-(void)moveToNewController:(UIViewController *) newController {
[self.currentController willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentController toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{}
completion:^(BOOL finished) {
[self.currentController removeFromParentViewController];
[newController didMoveToParentViewController:self];
self.currentController = newController;
}];
}
This should give you the basic idea. I took this from one of my test projects, so it will probably need a little tweaking.
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.
I am trying to display a modal viewController in an iPad app using the UIModalPresentationFormSheet view style. I am looking to produce something similar to the Mail app's new message UI/animation.
There are two things that are not behaving correctly:
The modal viewController that is presented always animates to y=0, i.e. to the very top of the
view and not some pixels below the status bar as it does in the mail app.
The documentation says:
UIModalPresentationFormSheet The width
and height of the presented view are
smaller than those of the screen and
the view is centered on the screen. If
the device is in a landscape
orientation and the keyboard is
visible, the position of the view is
adjusted upward so that the view
remains visible. All uncovered areas
are dimmed to prevent the user from
interacting with them.
However, in my case there is no dimming and I can still interact with the parentView below the modalViewController.
The controller that presents the modalView I do this:
AddNewItemViewController *newItemViewController = [[AddNewItemViewController alloc] initWithNibName:#"AddNewItemViewController" bundle:nil];
[self presentModalViewController:newItemViewController animated:YES];
[newItemViewController release];
In the viewController being presented I do this:
- (void)viewDidLoad {
[nameField becomeFirstResponder];
[self setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self setModalPresentationStyle:UIModalPresentationFormSheet];
[super viewDidLoad];
}
I hope someone can help me out.
Is there some other properties I need to set on the parent and modalViewController?
Is the viewDidLoad not the right place to do this setup?
Thanks in advance:)
You set the transition and presentation styles when you create the modal view, before you call presentModalViewController. Remember, the view that creates the modal view 'owns' that object. You want the owner to set these properties because you might implement this modal view elsewhere in the app and want different transition or presentation styles. This way, you set it each time as appropriate.
AddNewItemViewController *newItemViewController = [[AddNewItemViewController alloc] initWithNibName:#"AddNewItemViewController" bundle:nil];
newItemViewController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:newItemViewController animated:YES];
[newItemViewController release];
You're right in calling becomeFirstResponder in viewDidLoad.