15

I'm trying to make a custom alertView (for iOS7+) on my own but I struggle with the alertView presentation.

I have a UIViewController with a black background (alpha set to 0.25f), and a alertView as subview.

When I want to show the alertView, I present modally the viewController:

-(void) show 
{
    UIWindow* window = [[UIApplication sharedApplication] keyWindow];
    self.modalTransitionStyle = UIModalPresentationCustom;
    self.transitioningDelegate = self;
    [window.rootViewController presentViewController:self animated:YES completion:nil];
}

And here is my animator object:

-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    NSLog(@"%s",__PRETTY_FUNCTION__);
    return 2;
}

-(void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    NSLog(@"%s",__PRETTY_FUNCTION__);

    UIView* toView = [transitionContext viewForKey:UITransitionContextToViewKey];
    toView.alpha = 0;

    UIView* container = [transitionContext containerView];
    [container addSubview:toView];

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        toView.alpha = 0.5;
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];
    }];
}

The thing is: the modal VC is fading with the presenting VC in background as its supposed to do, but when the animation ends the presenting VC is removed from the background.

If I call [transitionContext completeTransition:YES]; instead, the presenting VC is in background but the modal VC is removed at animation end, so I guess the context cancels the presentation if we send 'NO'.

Is there a way to keep the presenting VC in background without having to make a snapshot of it and set it as background of the modal VC's view?

mohacs
  • 12,002
  • 9
  • 47
  • 76
Imotep
  • 1,865
  • 2
  • 22
  • 38

6 Answers6

42

I've tried this solution and it works on both iOS 7 and 8:

if ([[UIDevice currentDevice].systemVersion integerValue] >= 8)
{
    //For iOS 8
    presentingViewController.providesPresentationContextTransitionStyle = YES;
    presentingViewController.definesPresentationContext = YES;
    presentedViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
}
else
{
    //For iOS 7
    presentingViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
}

Note: Be aware of the difference between 'presentingViewController' and 'presentedViewController'.

Basem Saadawy
  • 1,778
  • 2
  • 19
  • 30
  • 4
    How da hell you don't have any upvotes? This is the best answer ever – jovanjovanovic Jan 14 '15 at 18:38
  • 2
    For full screen experience (specially when presenting from `UINavigationController`) use `presentedViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;` – tomec Feb 15 '15 at 11:24
  • good answer. this works for me also. only thing we need to take care is presented and presenting view controllers. – Ankit Nov 06 '16 at 11:37
  • I also had to add background color of presented viewcontroller with alpha property like : [self.view setBackgroundColor:[UIColor colorWithRed:170/255.0 green:170/255.0 blue:170/255.0 alpha:0.4]]; – Hima Feb 25 '18 at 15:56
5

iOS8+

For iOS8+ you can use below code snippet

SecondViewController *secondViewController = [[SecondViewController alloc] init];
secondViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;           
[self presentViewController:secondViewController animated:YES completion:nil];    
arunjos007
  • 3,749
  • 1
  • 22
  • 41
2

My case might differ from yours, but the information might be useful for the conversation.

In Storyboard, I changed my segue's Presentation to state "Over Full Screen" and it did the trick.

Carien van Zyl
  • 2,705
  • 19
  • 27
1

I think what you are seeing is the default behavior of iOS.

View controllers are not supposed to be non-opaque when presented as modal view controllers. iOS removes the underlaying view controller when the animation is complete, in order to speed up composition when the presented view controller is supposed to take up the entire screen. There is no reason to draw a view controller - which might be complex in it's view hierarchy - when it is not even visible on screen.

I think your only solution is to do a custom presentation.

Remark: I did not test this. But it goes something like this.

/* Create a window to hold the view controller. */
UIWindow *presenterWindow = [[UIWindow alloc] init];

/* Make the window transparent. */
presenterWindow.backgroundColor = [UIColor clearColor];
presenterWindow.opaque = NO;

/* Set the window rootViewController to the view controller you
   want to display as a modal. */
presenterWindow.rootViewController = myModalViewController;

/* Setup animation */
CGRect windowEndFrame = [UIScreen mainScreen].bounds;
CGRect windowStartFrame = windowEndFrame;

/* Adjust the start frame to appear from the bottom of the screen. */
windowStartFrame.origin.y = windowEndFrame.size.height;

/* Set the window start frame. */
presenterWindow.frame = windowStartFrame;

/* Put the window on screen. */
[presenterWindow makeKeyAndVisible];

/* Perform the animation. */
[UIView animateWithDuration:0.5
                      delay:.0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{
                     presenterWindow.frame = windowEndFrame;
                 }
                 completion:^(BOOL finished){
                     /* Your transition end code */
                 }];

This does however leave you with no option to use any of the presenting view controller logic build into UIViewController. You'll need to figure yourself, when the presented view controller is done, and then reverse the animation and remove the UIWindow from screen.

Trenskow
  • 3,603
  • 1
  • 26
  • 32
  • Looking at http://stackoverflow.com/questions/11236367/display-clearcolor-uiviewcontroller-over-uiviewcontroller/11252969#11252969, and more precisely at https://github.com/hightech/iOS-7-Custom-ModalViewController-Transitions, i think this is supposed to work. And more important, at the beginning my alertView was just a view I added to the app's window, but the view wasn't rotating. So I wrapped it in a VC to help him handle rotation. I think rotation isn't handled with your solution. – Imotep Aug 12 '14 at 11:17
1

The ViewController is not supposed to be transparent when you present it or push it. You can try adding it as subview. And for transition effect change its frame immediately after adding as subview. Make its frame somewhere outside the visible view and then animate it to change frame to visible view.

Hope this helps.

Nameet
  • 618
  • 8
  • 17
  • If I add it as a subview of the windows it won't rotate with the UI, and if i add it as a subview of the top VC the transparent background won't cover all of the UI. – Imotep Aug 12 '14 at 13:48
1

For your information, I finally made my custom alertView a subclass of UIView for the "popUp part". To show it, I just add the alertView as subview of the keyWindow with the constraints to center it, and put a transparent black background view behind it.

As it's not a controller, I have to manage UI rotation by myself (only for iOS 7, it rotates well with the UI in iOS 8).

Imotep
  • 1,865
  • 2
  • 22
  • 38