When i press a button on my view controller, i would like to present another controller on top of it, but in the middle and not in full screen.
How could i present a controller on top of another controller in such way?
If you are trying it on iPad you can always set up a Popover that contains your new view.
UIYourNewViewController *vc = [[UIYourNewViewController alloc] init];
UIPopoverController *popVc = [[UIPopoverController alloc] initWithContentViewController:vc];
[popVc setPopoverContentSize:*the size that you want or your resized vc*];
[popVc presentPopoverFromRect:*position of the screen you want to show the popover* inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
With this you will create a Popover of the size of the view of your viewcontroller and you can pop it up in the position that you want.
To make sure it works on iPhone also, you should create a category for the UIPopoverController and add this method in the .m
+ (BOOL)_popoversDisabled {
return NO;
}
Remember to declare the method in the .h of the category.
You need to set this property to your controller before presenting it.
controller.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:controller animated:YES completion:nil];
Yes it is possible you have to present view controllers view with animation. Please refer the below code. You will get some idea its showing animation from bottom of screen to middle of screen.
YourViewController *viewController = [[YourViewController alloc] init];
[viewController.view setFrame:CGRectMake(0, -(CGRectGetHeight(viewController.view.frame)), CGRectGetWidth(viewController.view.frame), CGRectGetHeight(self.view.frame))];
[self.view addSubview:viewController.view];
[UIView animateWithDuration:0.8 animations:^{
[viewController.view setFrame:CGRectMake(0, 0, CGRectGetWidth(viewController.view.frame), CGRectGetHeight(viewController.view.frame))];
} completion:^(BOOL finished) {
[self.navigationController pushViewController:viewController animated:NO];
}];
In iPhone, presenting a UIViewController is always fullscreen. On iPad, you can use a UISplitViewController or build a custom container, but the view controllers you present will fill the containers in both a UISplitViewController and custom container controller.
To present content on only part of the screen, you can animate a UIView onto your view controller. There are ways to present a view controller and still have another view controller show up behind it, but this is not recommended.
Check out this other question for more information on creating a custom container view controller..
I am creating a viewcontroller in this way:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"PhotoViewControlleriPhone" bundle:nil];
UIViewController *vc = [sb instantiateInitialViewController];
vc.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:vc animated:NO];
vc.view.frame = CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y + 64, imageView.frame.size.width, 200.000000);
vc.view.layer.cornerRadius = 10; // this value vary as per your desire
vc.view.clipsToBounds = YES;
The viewcontroller is not full screen, so you can still see the previous one. I want to be able to see it, but lock it. Just like when you use ios facebook sharing, you see the background, but it becomes darker and you can't interact with it. How can I do this?
I believe the problem is that you’re displaying it using -presentModalViewController:animated:. Using that method carries with it some assumptions about the view controller you’re hosting; one of the assumptions it makes (on iPhone-type devices, at least) is that the view controller takes up the entire screen and is opaque.
To get around this, try adding the modal view controller’s view to the current view controller’s view manually. You’ll need to set the view controller hierarchy up to match the view hierarchy, so your code would look like this:
[self addChildViewController:vc];
[self.view addSubview:vc.view];
You’ll need to adjust the incoming view’s frame to position it within its new superview, but that should allow you more freedom.
My workaround is to take a screenshot with code, pass the UIImage as a parameter to the new UIViewController, and display it as a background image. In that way it appears transparent, and the you don't have to disable the underlying controls that might be reachable/accessible.
iOS8+
You can use below code snippet for iOS8+, its worked for me
SecondViewController *secondViewController = [[SecondViewController alloc] init];
secondViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:secondViewController animated:YES completion:nil];
I would like to present a view controller full screen semi-transparently so that I still see the view underneath it. The following code presents the new view controller, but it replaces the current one. What is the best way to keep the original view controller visible? The view of the new view controller will have a semi-transparent black background.
NewViewController* newVC = [[NSClassFromString(#"NewViewController") alloc] initWithNibName:deviceNib bundle:nil];
newVC.modalPresentationStyle = UIModalPresentationFullScreen;
newVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:newVC animated:YES completion:NULL];
Present a semi-transparent View, not a view controller.
mySemiTransparentView.alpha = 0.0f;
[self.view addSubview:mySemiTransparentView];
mySemiTransparentView is your full-screen view. You can animate it into place:
[UIView beginAnimations:#"fadeIn" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:0.4f];
mySemiTransparentView.alpha = 0.5f;
[UIView commitAnimations];
You can present semi-transparent modal controller in the following way:
NewViewController* newVC = [[NSClassFromString(#"NewViewController") alloc] initWithNibName:deviceNib bundle:nil];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
newVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:newVC animated:YES completion:NULL];
Notice here that you have to set the constant UIModalPresentationCurrentContext to self.modalPresentationStyle, not to newVC.modalPresentationStyle
Furthermore, when you use UIModalTransitionStyleCrossDissolve the alpha of the newVC.view will be overridden during the transition, so if you want semi-transparent background you'll need to keep newVC.view's backgroundColor clear and just add another UIView as it's subview with semi-transparent backgroundColor
I'm able to implement the concept of childviewcontroller in my PhoneGap project.
Now when I click on any link of my app, that opens in childviewcontroller successfully.
Here is a line that opens the page in clildbrowser
[super.viewController presentModalViewController:childBrowser
animated:YES ];
Now I want to open childBrowser as a pushViewController. Currently it comes from bottom to top but i want this to open from left to right.
Is there any way? Replacing presentModalViewController to pushViewController fails.
presentModalViewController and pushViewController ar every different in concept.
If you just need to change the animation, you might want to do something like this:
childBrowser.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
//childBrowser.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
//childBrowser.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//childBrowser.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[super.viewController presentModalViewController:modalViewController
animated:YES];
or simply use traditional animations (code needs adapting):
UIViewController *controller = [[[MyViewController alloc] init] autorelease];
UIViewAnimationTransition trans = UIViewAnimationTransitionCurlUp;
[UIView beginAnimations: nil context: nil];
[UIView setAnimationTransition: trans forView: [self window] cache: YES];
[navController presentModalViewController: controller animated: NO];
[UIView commitAnimations];
I am displaying a modal view with
[self presentModalViewController:controller animated:YES];
When the view moves up the screen it is transparent as per the setting in the xib file it is created from, but once it fills the screen it goes opaque.
Is there anyway of keeping the view transparent?
I suspect that the view it is being placed over is not being rendered rather then that the modal view is becoming opaque.
After iOS 3.2 there is a method to do this without any “tricks” – see the documentation for the modalPresentationStyle property. You have a rootViewController which will present the viewController.
So here's the code to success:
viewController.view.backgroundColor = [UIColor clearColor];
rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[rootViewController presentModalViewController:viewController animated:YES];
With this method the viewController's background will be transparent and the underlying rootViewController will be visible. Please note that this only seems to work on the iPad, see comments below.
Your view is still transparent, but once your modal controller is at the top of the stack, the view behind it is hidden (as is the case with any top-most view controller). The solution is to manually animate a view yourself; then the behind-viewController won't be hidden (since you won't have 'left' it).
What I needed to get this to work:
self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
For those who want to see some code, here's what I added to my transparent view's controller:
// Add this view to superview, and slide it in from the bottom
- (void)presentWithSuperview:(UIView *)superview {
// Set initial location at bottom of superview
CGRect frame = self.view.frame;
frame.origin = CGPointMake(0.0, superview.bounds.size.height);
self.view.frame = frame;
[superview addSubview:self.view];
// Animate to new location
[UIView beginAnimations:#"presentWithSuperview" context:nil];
frame.origin = CGPointZero;
self.view.frame = frame;
[UIView commitAnimations];
}
// Method called when removeFromSuperviewWithAnimation's animation completes
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context {
if ([animationID isEqualToString:#"removeFromSuperviewWithAnimation"]) {
[self.view removeFromSuperview];
}
}
// Slide this view to bottom of superview, then remove from superview
- (void)removeFromSuperviewWithAnimation {
[UIView beginAnimations:#"removeFromSuperviewWithAnimation" context:nil];
// Set delegate and selector to remove from superview when animation completes
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
// Move this view to bottom of superview
CGRect frame = self.view.frame;
frame.origin = CGPointMake(0.0, self.view.superview.bounds.size.height);
self.view.frame = frame;
[UIView commitAnimations];
}
The Apple-approved way to do this in iOS 8 is to set the modalPresentationStyle to 'UIModalPresentationOverCurrentContext'.
From the UIViewController documentation:
UIModalPresentationOverCurrentContext
A presentation style where the content is displayed over only the
parent view controller’s content. The views beneath the presented
content are not removed from the view hierarchy when the presentation
finishes. So if the presented view controller does not fill the screen
with opaque content, the underlying content shows through.
When presenting a view controller in a popover, this presentation
style is supported only if the transition style is
UIModalTransitionStyleCoverVertical. Attempting to use a different
transition style triggers an exception. However, you may use other
transition styles (except the partial curl transition) if the parent
view controller is not in a popover.
Available in iOS 8.0 and later.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/
The 'View Controller Advancements in iOS 8' video from WWDC 2014 goes into this in some detail.
Be sure to give your presented view controller a clear background color (otherwise, it will still appear opaque).
There is another option: before showing the modal controller, capture a screenshot of the whole window. Insert the captured image into an UIImageView and add the image view to the controller's view you're about to show.
Then send to back.
Insert another view above the image view (background black, alpha 0.7).
Show your modal controller and it looks like it was transparent.
Just tried it on iPhone 4 running iOS 4.3.1. Like charm.
this is quite old, but i solved the same problem as follows:
Since i need to present a navigation controller in iPhone, adding a subview wasn't a viable solution.
So what i did:
1) Before presenting the view controller, take a screenshot of your current screen:
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
2) Create the view controller you want to present, and add the background as a subview, sending it to back.
UIViewController * presentingVC = [UIViewController new];
UIImageView * backgroundImageOfPreviousScreen = [[UIImageView alloc] initWithImage:backgroundImage];
[presentingVC.view addSubview:backgroundImageOfPreviousScreen];
[presentingVC.view sendSubviewToBack:backgroundImageOfPreviousScreen];
3) Present your view controller, but before that in the new view controller, add a transparent view in the viewDidLoad (i used ILTranslucentView)
-(void)viewDidLoad
{
[super viewDidLoad];
ILTranslucentView * translucentView = [[ILTranslucentView alloc] initWithFrame:self.view.frame];
[self.view addSubview:translucentView];
[self.view sendSubviewToBack:translucentView];
}
And that's all!
I wrote down my findings about this in a different question, but the gist of it is that you have to call modalPresentationStyle = UIModalPresentationCurrentContext on whatever owns the full screen at the moment. Most of the time, it's whatever is the [UIApplication sharedApplication].delegate.window's rootViewController. It could also be a new UIViewController that was presented with modalPresentationStyle = UIModalPresentationFullScreen.
Please read my other much more detailed post if you're wondering how I specifically solved this problem. Good luck!
This appears to be broken in IOS 8, I am using a navigation controller and the context that is being displayed is the Navigation menus context which in our case is a sliding Menu controller.
We are using pod 'TWTSideMenuViewController', '0.3' have not checked to see if this is an issue with the library yet or the method described above.
This worked to me in iOS 8-9:
1- Set your view controller's background with an alpha
2- add this code:
TranslucentViewController *tvc = [[TranslucentViewController alloc] init];
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[tvc setModalPresentationStyle:UIModalPresentationOverCurrentContext];
[self.navigationController presentViewController:tvc animated:YES completion:nil];
I know this is pretty old question. I was stuck on this issue and I was able to get a lead from this thread. So putting here how I got it worked :) .
I am using storyboard and I have segue to the ViewController which is to be presented. The view controller have a transparent background colour. Now in the Attributes inspector of the segue I set the presentation to "Over current context".And it worked for me. I am developing for iPhone.
I've created open soruce library MZFormSheetController to present modal form sheet on additional UIWindow. You can use it to present transparency modal view controller, even adjust the size of the presented view controller.
In my condition i am having view on same viewController. So make a new view controller for holding UIView. Make that view transparent by setting it's alpha property.
Then on a button click i wrote this code. It looks good.
UIGraphicsBeginImageContext(objAppDelegate.window.frame.size);
[objAppDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIViewController *controllerForBlackTransparentView=[[[UIViewController alloc] init] autorelease];
[controllerForBlackTransparentView setView:viewForProfanity];
UIImageView *imageForBackgroundView=[[UIImageView alloc] initWithFrame:CGRectMake(0, -20, 320, 480)];
[imageForBackgroundView setImage:viewImage];
[viewForProfanity insertSubview:imageForBackgroundView atIndex:0];
[self.navigationController presentModalViewController:controllerForBlackTransparentView animated:YES];
And it shows what i want. hope it help some one.
Here's a category I've created that will solve the problem.
//
// UIViewController+Alerts.h
//
#import <UIKit/UIKit.h>
#interface UIViewController (Alerts)
- (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated;
- (void)dismissAlertViewControllerAnimated:(BOOL)animated;
#end
//
// UIViewController+Alerts.m
//
#import "UIViewController+Alerts.h"
#implementation UIViewController (Alerts)
- (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated
{
// Setup frame of alert view we're about to display to just off the bottom of the view
[alertViewController.view setFrame:CGRectMake(0, self.view.frame.size.height, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];
// Tag this view so we can find it again later to dismiss
alertViewController.view.tag = 253;
// Add new view to our view stack
[self.view addSubview:alertViewController.view];
// animate into position
[UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
[alertViewController.view setFrame:CGRectMake(0, (self.view.frame.size.height - alertViewController.view.frame.size.height) / 2, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];
}];
}
- (void)dismissAlertViewControllerAnimated:(BOOL)animated
{
UIView *alertView = nil;
// find our tagged view
for (UIView *tempView in self.view.subviews)
{
if (tempView.tag == 253)
{
alertView = tempView;
break;
}
}
if (alertView)
{
// clear tag
alertView.tag = 0;
// animate out of position
[UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
[alertView setFrame:CGRectMake(0, self.view.frame.size.height, alertView.frame.size.width, alertView.frame.size.height)];
}];
}
}
#end
After a lot of research looks like this will solve our issue and serve our purpose.
create a segue from source VC to destination VC with an identifier.
for example "goToDestinationViewController"
okay to makes lives easy let's consider the current view controller i.e, the one you want behind your transparent view as source and the destination as destination
Now in source VC in viewDidLoad: or view
performSegueWithIdentifier("goToDestinationViewController", sender: nil)
good we are half way through.
Now go to your storyboard. Click on the segue. which should look like this:
segue
change the options to what are shown.
Now comes the real solution.
in your destination view controller's viewDidLoad add this code.
self.modalPresentationStyle = .Custom
.........................................................................THAT EASY..................................................................
Alternate way is to use a "container view". Just make alpha below 1 and embed with seque.
XCode 5, target iOS7.
can't show image, not enough reputation)))
Container view available from iOS6.
This code works fine on iPhone under iOS6 and iOS7:
presentedVC.view.backgroundColor = YOUR_COLOR; // can be with 'alpha'
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:YES completion:NULL];
But along this way you loose 'slide-from-the-bottom' animation.
I found this elegant and simple solution for iOS 7 and above!
For iOS 8 Apple added UIModalPresentationOverCurrentContext, but it does not work for iOS 7 and prior, so I could not use it for my case.
Please, create the category and put the following code.
.h file
typedef void(^DismissBlock)(void);
#interface UIViewController (Ext)
- (DismissBlock)presentController:(UIViewController *)controller
withBackgroundColor:(UIColor *)color
andAlpha:(CGFloat)alpha
presentCompletion:(void(^)(void))presentCompletion;
#end
.m file
#import "UIViewController+Ext.h"
#implementation UIViewController (Ext)
- (DismissBlock)presentController:(UIViewController *)controller
withBackgroundColor:(UIColor *)color
andAlpha:(CGFloat)alpha
presentCompletion:(void(^)(void))presentCompletion
{
controller.modalPresentationStyle = UIModalPresentationCustom;
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
__block UIView *overlay = [[UIView alloc] initWithFrame:keyWindow.bounds];
if (color == nil) {
color = [UIColor blackColor];
}
overlay.backgroundColor = color;
overlay.alpha = alpha;
if (self.navigationController != nil) {
[self.navigationController.view addSubview:overlay];
}
else if (self.tabBarController != nil) {
[self.tabBarController.view addSubview:overlay];
}
else {
[self.view addSubview:overlay];
}
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:controller
animated:true
completion:presentCompletion];
DismissBlock dismissBlock = ^(void) {
[self dismissViewControllerAnimated:YES completion:nil];
[UIView animateWithDuration:0.25
animations:^{
overlay.alpha = 0;
} completion:^(BOOL finished) {
[overlay removeFromSuperview];
}];
};
return dismissBlock;
}
#end
Note: it works also for navigationContoller, tabBarController.
Example of usage:
// Please, insure that your controller has clear background
ViewController *controller = [ViewController instance];
__block DismissBlock dismissBlock = [self presentController:controller
withBackgroundColor:[UIColor blackColor]
andAlpha:0.5
presentCompletion:nil];
// Supposed to be your controller's closing callback
controller.dismissed = ^(void) {
dismissBlock();
};
Enjoy it! and please, leave some feedbacks.
This is the best and cleanest way I found so far:
#protocol EditLoginDelegate <NSObject>
- (void)dissmissEditLogin;
#end
- (IBAction)showtTransparentView:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"foo bar"
delegate:self
cancelButtonTitle:#"cancel"
destructiveButtonTitle:#"destructive"
otherButtonTitles:#"ok", nil];
[actionSheet showInView:self.view];
}
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet{
UIStoryboard *loginStoryboard = [UIStoryboard storyboardWithName:#"Login" bundle:nil];
self.editLoginViewController = [loginStoryboard instantiateViewControllerWithIdentifier:#"EditLoginViewController"];
self.editLoginViewController.delegate = self;
[self.editLoginViewController viewWillAppear:NO];
[actionSheet addSubview:self.editLoginViewController.view];
[self.editLoginViewController viewDidAppear:NO];
}
The best solution I have come across is to use the addChildViewController method.
Here is an excellent example : Add a child view controller's view to a subview of the parent view controller
I try to use multiple methods to solve but still failed, the follow code implemented finally.
The resolution by Swift:
// A.swift init method
modalPresentationStyle = .currentContext // or overCurrentContent
modalTransitionStyle = .crossDissolve // dissolve means overlay
then in B view controller:
// B.swift
let a = A()
self.present(a, animated: true, completion: nil)