I have made a class with xib file called TopHeaderViewController now i use another class named iShared that as a Shared instance method.
In iShared i have a #property called topHeader now when i first call sharedInstance on iShared i call: topHeader = [[TopHeaderViewController alloc]init]; and every time i navigate through another viewController i put this view on the top of the view controller.
The view appear correctly but the button doesn't fire event.
Code for viewController:
- (void)viewDidLoad {
[super viewDidLoad];
ishared = [iShared sharedInstance];
// Do any additional setup after loading the view.
UIView *v = [ishared initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, headerView.frame.size.height)];
[headerView addSubview:v];
}
Code for iShared:
- (id)init
{
self = [super init];
topHeaderVC = [[TopHeaderViewController alloc]init];
}
code for TopHeaderViewController:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
mainMenuController =[[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"mainMenuController"];
mainMenuController.superViewController = superViewController;
mainMenuController.view.frame = CGRectMake(0, self.view.frame.size.height, mainMenuController.view.frame.size.width, mainMenuController.view.frame.size.height);
[topView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"sfondo_nero_sfumato"]]];
[topView setFrame:CGRectMake(topView.frame.origin.x , topView.frame.origin.y, superViewController.view.frame.size.width, topView.frame.size.height)];
ishared = [iShared sharedInstance];
[self aggiornaTicketNotificationValue_betCoupon:ishared.betCoupon];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:NOTIFICATION_AGGIORNA_TOPHEADER_COUPON_LABEL
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:NOTIFICATION_AGGIORNA_TOPHEADER_ACCOUNT_DETAIL
object:nil];
}
- (IBAction)mnClick:(id)sender {
iShared *ishared = [iShared sharedInstance];
if (![ishared menuAperto]){
[UIView animateWithDuration:0.5
delay: 0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
mainMenuController.view.alpha = 1.0;
}
completion:nil];
[UIView commitAnimations];
[superViewController.view addSubview:mainMenuController.view];
ishared.menuAperto = true;
}else{
[UIView animateWithDuration:0.5
delay: 0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
mainMenuController.view.alpha = 0;
}
completion:nil];
[UIView commitAnimations];
[mainMenuController.view removeFromSuperview];
ishared.menuAperto = false;
}
}
anyone knows why i'm getting this trouble to get my button work?
Thanks
The problem is that what you're doing is totally illegal and incoherent. You cannot just shove a view controller's view into your interface. View controllers have a structural hierarchy that parallels their views, and you are completely disregarding that. The result is that you end up with the view without the view controller.
So what should you do? Well, we can look at it from two directions. One is that you might want to know how to insert a view controller's view correctly into your interface. The answer is that you have to make that view controller a child of your current view controller, and do a careful "custom container controller" dance, as I describe here.
However, I would suggest that that is not what you want to do here. The fact is, it seems to me, that your situation is just an inappropriate use of a view controller. You don't need a view controller here at all. You are just using the view controller in effect to go "dumpster diving" to retrieve the view designed the xib file. But you do not need a view controller to do that! You can do everything you want to do here just using a xib file and view subclasses that embody the desired functionality.
SET UP
In my view controller i have a View and 2 Buttons
everything positioned in a Storyboard, and linked to ViewController.h
STEP 1 : I push the 1st button to make the View move.
STEP 2 : I push the 2nd button to pop the UIActionSheet.
PROBLEM
As soon as I push the 2nd button, my View position comes back as defined in the storyboard.
Here is my code :
ViewController.h
#interface ViewController : UIViewController<UIActionSheetDelegate>
#property (strong, nonatomic) IBOutlet UIView *view1;
- (IBAction)move:(id)sender;
- (IBAction)bringPop:(id)sender;
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
//move _View1
- (IBAction)move:(id)sender {
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
_view1.layer.frame= CGRectMake(0, 79, 320, 489);
} completion:nil];
}
//action sheet pops
- (IBAction)bringPop:(id)sender {
UIActionSheet *popupQuery = [[UIActionSheet alloc] initWithTitle:#"" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"0" otherButtonTitles:#"1", #"2", #"3", nil];
[popupQuery showInView:self.view];
}
#end
You might need to overwrite the method
-(void)layoutSubviews
This method should be overwritten when the AutoLayout or AutoResizingMasks doesn't perform the layout that you require. I'm pretty sure that the UIActionSheet presents itself as a modalViewController which triggers a viewDidAppear and viewWillAppear in your actual ViewController.
Try setting some break points and check if this methods are triggered if so then AutoLayout or AutoResizingMasks are resetting your frames as in the xib file.
It will depend a lot on how are you building your views
You're setting the view's layer's frame, rather than just the view's frame
The animation block should be
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
_view1.frame= CGRectMake(0, 79, 320, 489);
} completion:nil];
I am trying to debug a really weird issue in the following code:
if(condition1) {
ImageViewController* imageViewer = [[ImageViewController alloc] initWithImageData:tappedItem];
[self presentViewController:imageViewer animated:YES completion:^{
[imageViewer loadImage];
}];
}
else if(condition2) {
DocumentViewController* docViewer = [[DocumentViewController alloc] init];
[self presentViewController:docViewer animated:YES completion:nil];
}
In other words, depending on the state of condition1 and condition2, one of two subclasses of UIViewController will be displayed modally to the user.
In the second case all is well, but in the first the view controller is not presented with the usual animation that shows it sliding in from the bottom of the screen. Instead, after a brief delay, it just shows up all of a sudden, covering the entire screen. Another oddity is that in the dismissal animation, the image view inside the view controller is transparent.
Removing the completion block has no effect. Replacing my view controller with an instance of UIViewController also has no effect, other than demonstrating that for some reason, animations don't work for UIViewController instances either.
Thinking that maybe I did something wrong in viewDidLoad etc, I tried commenting out the view load/appear methods but to no avail.
Pushing the view controller onto the nav stack is not an option because the app has a tab bar and I don't want to be visible.
update
Replacing my instance of ImageViewController with a DocumentViewController does result in an animation. The question now becomes: what could I have done in ImageViewController to mess up the animation?
I've found a solution but I still have no idea what the real cause was.
The fix was to set a background color for the view of the UIViewController being displayed modally in its viewDidload method e.g.
self.view.backgroundColor = [UIColor grayColor];
If I ever figure out what really happened, I will post here.
How about presenting the view controller on the tab bar controller:
if(condition1) {
ImageViewController* imageViewer = [[ImageViewController alloc] initWithImageData:tappedItem];
[self.tabBarController presentViewController:imageViewer animated:YES completion:^{
[imageViewer loadImage];
}];
}
else if(condition2) {
DocumentViewController* docViewer = [[DocumentViewController alloc] init];
[self.tabBarController presentViewController:docViewer animated:YES completion:nil];
}
It happened to me as well.. changing the background colour didn't really help.
I did the following - it turns up to be quite nice:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:NO];
self.view.userInteractionEnabled = FALSE;
self.view.hidden = TRUE;
self.navigationController.navigationBar.alpha = 0;
}
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:NO];
float width = self.view.frame.size.width;
float height = self.view.frame.size.height;
self.view.frame = CGRectMake(0, height, width, height);
self.view.hidden = FALSE;
[UIView animateWithDuration:0.7f animations:^{
self.view.frame = CGRectMake(0, 0, width, height);
self.navigationController.navigationBar.alpha = 1;
} completion:^(BOOL finished){
self.view.userInteractionEnabled = TRUE;
}];
}
Setting the background color works for me in iOS 8.
Also uncheck the opaque setting in the Interface Builder works!
I am using a split view controller in a simple app. Leaving everything as default works fine. In other words, the master view controller always shows in landscape and overlays the detail view controller in portrait when the back button is pressed.
What I wanted to do was make the master view controller mimic the same functionality in landscape as it does in portrait. In other words, when the device is in landscape, I want the master view controller to be hidden until I hit the back button and then I want it to overlay the detail view controller.
I figured the best way to do this was to use the following code:
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController: (UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return self.bHideMaster;
}
This worked in that it hid the master view controller in landscape mode. I then used the following code to make it reappear:
- (void)hideUnhidePagesController:(id)sender
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.30f];
UISplitViewController* spv = self.splitViewController;
// Change hide to unhide or vica versa
self.bHideMaster= !self.bHideMaster;
// Hide the button if master is visible
if(self.bHideMaster)
{
self.navigationItem.leftBarButtonItem = self.pagesBarButton;
}
else
{
self.navigationItem.leftBarButtonItem = nil;
}
[spv.view setNeedsLayout];
[spv willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
[[self.splitViewController.viewControllers lastObject] view].frame = self.splitViewController.view.frame;
[UIView commitAnimations];
}
This ALMOST worked. I have 2 problems:
The transition from hide-to-unhide and unhide-to-hide the master view controller isn't animated and is much to stark. I added animation code (see above) but it only animates the detail view controller and not the master view controller. The master appears and dis-appears instantly (leaving a black box on disappear) until the detail view controller slides over.
This also shows my second problem. I want the master view controller to overlap the detail view controller when it appears in landscape mode, leaving the detail view controller as is. Instead, it resizes the detail view controller (the same way it does in landscape mode before I started). I want the master view controller to interact the same way it does in portrait mode: Master slides in over the top of the detail controller and slides back out when it an item is selected.
If I could solve problem 2, then I don't have to worry about problem 1. It seems like there should be a method in the split view controller that would slide in the master from the left (overlapping the detail view controller). It does it in portrait mode so the code must be there. How can I call that same code in landscape mode?
Thanks!
---------EDIT 1---------
I have refactored hideUnhidePagesController and am getting closer. The window now overlays in both portrait and landscape. There is still a problem if the master is visible on rotation. It gets confused and inverts the expected behavior. I'm working on it. Here the amended code:
- (void)hideUnhidePagesController:(id)sender
{
// Change hide to unhide or vica versa
self.bMasterIsHidden= !self.bMasterIsHidden;
NSArray *controllers = self.splitViewController.viewControllers;
UIViewController *rootViewController = [controllers objectAtIndex:0];
UIView *rootView = rootViewController.view;
CGRect rootFrame = rootView.frame;
if(self.bMasterIsHidden)
{
rootFrame.origin.x -= rootFrame.size.width;
}
else
{
rootFrame.origin.x += rootFrame.size.width;
}
[UIView beginAnimations:#"hideUnhideView" context:NULL];
rootView.frame = rootFrame;
[UIView commitAnimations];
}
In ios 8.0
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
to hide master view
To get the effect you describe I had to add the following code to my DetailViewController.
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:
(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return YES;
}
Then my split view works the same in portrait and landscape mode.
I'm putting in the code that I ended up using. Hope this helps someone else.
// ***************************************************************************************************
//
// hideUnhideMasterViewControllerButtonPressed
//
// ***************************************************************************************************
- (void)hideUnhideMasterViewControllerButtonPressed:(id)sender {
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
[self.navigationController popViewControllerAnimated:YES];
}
else {
if(bMasterIsHidden)
[self hideMasterViewController:NO];
else
[self hideMasterViewController:YES];
}
}
// ***************************************************************************************************
//
// hideMasterViewController
//
// ***************************************************************************************************
- (void)hideMasterViewController:(BOOL)bHideMaster {
// Change hide to unhide or vica versa
self.bMasterIsHidden= !self.bMasterIsHidden;
NSArray *controllers = self.splitViewController.viewControllers;
UIViewController *rootViewController = [controllers objectAtIndex:0];
UIView *rootView = rootViewController.view;
CGRect rootFrame = rootView.frame;
if(bHideMaster) {
if(self.tapRecognizer) {
rootFrame.origin.x -= rootFrame.size.width;
[self.view removeGestureRecognizer:self.tapRecognizer];
self.tapRecognizer = nil;
}
}
else {
rootFrame.origin.x += rootFrame.size.width;
self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapRecognized:)];
self.tapRecognizer.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:self.tapRecognizer];
self.tapRecognizer.delegate = self;
}
// Log resulting frame
NSString *hiddenString = self.bMasterIsHidden ? #"YES" : #"NO";
NSLog(#"Page=%# Class=%# MasterIsHidden=%# Origin(x,y)=(%f, %f) Size(width,height)=(%f, %f)", self.pageDefinition.pageName, [self class], hiddenString, rootFrame.origin.x, rootFrame.origin.y, rootFrame.size.width, rootFrame.size.height);
[UIView beginAnimations:#"hideUnhideView" context:NULL];
rootView.frame = rootFrame;
[UIView commitAnimations];
}
Maybe I am too late to answer this but... here is the solution..
You can get the reference of your masterviewcontroller from the method in every orientation change
-(BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation {
myVCForPopOverController = vc;
//always hide the controller
return YES;
}
now you can show this "myVCForPopOverController" from any barbutton items click.
-(void)onBarButtonClick:(id)sender {
if(!self.popOverController.popoverVisible) {
self.popOverController = [[UIPopoverController alloc]initWithContentViewController:myVCForPopOverController];
[self.popOverController presentPopoverFromBarButtonItem:showDetailsBarButton permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
self.popOverController.passthroughViews = nil;
}
else {
[self.popOverController dismissPopoverAnimated:YES];
}
}
I have implemented this and it works.
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)