How to change Modal background color to transparent in Objective-C
Asked Answered
S

5

9

I would like to have a modal view with a transparent background color, so that the view behind it can be seen by user.

Sarita answered 27/12, 2010 at 9:10 Comment(7)
you can use the [UIcolor clearcolor];Cyndicyndia
What modal dialog are you using?Riddell
@Raxit: when i set the background color with clear color that not make we can see the view behind the modal.Sarita
@BoltClock: yes, this is for iOS @Eiko: what do you mean with What modal dialog am i using?Sarita
In your question you have mentioned "I want the view behind modal can be seen by user." so is it right ? or you want to say something different. Please describe what exactly you wanted to do ?Cyndicyndia
@Raxit: I used form sheet modal so the modal is beetween transparent view. From that transparent view, we can look the view behind. So, I want my modal can look like that transparent view. When I used clear color that just diplay grey color not the view behind the modal.Sarita
possible duplicate of Transparent Modal View on Navigation ControllerTophet
D
3

iOS doesn't support transparency when presenting a view modally.

Deka answered 16/2, 2011 at 13:53 Comment(2)
Yes I think. Till now iOS doesn't support transparency in modal. Thanks for your answer machunter. :)Sarita
well, knowing that does not help thoughDipole
I
10

Okay, so presentModalViewController doesn't offer this behavior... However it is still possible. I've created a category that works for me (and hopefully you). As an added bonus, it also prevents crashes related to dismissing and presenting modal views at the same time!

Header file:

//
//  UIViewController+overView.h
//  Created by Kevin Lohman on 5/30/12.
//

#import <UIKit/UIKit.h>

@interface UIViewController (OverView)
- (void)presentOverViewController:(UIViewController *)modalViewController animated:(BOOL)animated;
- (void)dismissOverViewControllerAnimated:(BOOL)animated;
@end

Implementation File:

//
//  UIViewController+overView.m
//  Created by Kevin Lohman on 5/30/12.
//

#import "UIViewController+overView.h"

@implementation UIViewController (OverView)

#define kUIViewControllerOverViewDismissNotification @"OverViewDismissNotification"

const float kUIViewControllerOverViewAnimationDuration = 0.75;
const NSInteger kUIViewControllerOverViewTag = 8008135; // Arbitrary number, so as not to conflict
- (void)overViewDismissed
{
    [self autorelease];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kUIViewControllerOverViewDismissNotification object:self.view];
}

- (void)presentOverViewController:(UIViewController *)modalViewController animated:(BOOL)animated
{
    UIView *toView = self.view;

    CGRect finalRect = CGRectIntersection([[UIScreen mainScreen] applicationFrame], self.view.frame); // Make sure it doesn't go under menu bar
    modalViewController.view.frame = finalRect;
    modalViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
    modalViewController.view.tag = kUIViewControllerOverViewTag+modalViewController.modalTransitionStyle; // Hiding some info here :)

    if(animated)
    {
        switch(modalViewController.modalTransitionStyle)
        {
            // Currently only cross dissolve and cover vertical supported... if you add support let me know.
            case UIModalTransitionStyleCrossDissolve:
            {
                float beforeAlpha = modalViewController.view.alpha;
                modalViewController.view.alpha = 0;
                [toView addSubview:modalViewController.view];
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    modalViewController.view.alpha = beforeAlpha;
                }];
                break;
            }
            case UIModalTransitionStyleCoverVertical:
            default:
            {
                modalViewController.view.frame = CGRectMake(modalViewController.view.frame.origin.x, modalViewController.view.frame.size.height, 
                                                            modalViewController.view.frame.size.width, modalViewController.view.frame.size.height);
                [toView addSubview:modalViewController.view];
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    modalViewController.view.frame = finalRect;
                }];
                break;
            }
        }
    }
    else {
        [toView addSubview:modalViewController.view];
    }

    [modalViewController retain]; // Keep it around until we dismiss it.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(overViewDismissed) name:kUIViewControllerOverViewDismissNotification object:modalViewController.view]; // Release will happen when this notification is posted
}

NSInteger transitionStyleForTag(tag)
{
    if (tag >= kUIViewControllerOverViewTag && tag <= kUIViewControllerOverViewTag+UIModalTransitionStylePartialCurl)
    {
        return tag-kUIViewControllerOverViewTag;
    }
    else {
        return -1; // Not a Over View
    }
}

- (void)dismissOverViewControllerAnimated:(BOOL)animated
{
    UIView *overView = transitionStyleForTag(self.view.tag) >= 0 ? self.view : nil; // Can dismiss ourselves
    for(UIView *subview in self.view.subviews)
    {
        if(transitionStyleForTag(subview.tag) >= 0)
            overView = subview; // Keep going, lets dismiss last presented first
    }
    if(!overView) return; // None to dismiss

    if(animated)
    {
        switch(transitionStyleForTag(overView.tag))
        {
            // Currently only cross dissolve and cover vertical supported... if you add support let me know.
            case UIModalTransitionStyleCrossDissolve:
            {
                float beforeAlpha = overView.alpha;
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    overView.alpha = 0;
                } completion:^(BOOL finished) {
                    [overView removeFromSuperview];
                    overView.alpha = beforeAlpha;
                    [[NSNotificationCenter defaultCenter] postNotificationName:kUIViewControllerOverViewDismissNotification object:overView];
                }];
                break;
            }
            case UIModalTransitionStyleCoverVertical:
            default:
            {
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    overView.frame = CGRectMake(0, overView.frame.size.height, overView.frame.size.width, overView.frame.size.height);
                } completion:^(BOOL finished) {
                    [overView removeFromSuperview];
                    [[NSNotificationCenter defaultCenter] postNotificationName:kUIViewControllerOverViewDismissNotification object:overView];
                }];
                break;
            }
        }
    }
    else {
        [overView removeFromSuperview];
        [[NSNotificationCenter defaultCenter] postNotificationName:kUIViewControllerOverViewDismissNotification object:overView];
    }
}
@end

And then to use it, simply use presentOverViewController instead of presentModalViewController and dismissOverViewController instead of dissmissModalViewController.

There are a couple of limitations:

  1. You have to present to the root-most view controller, so if you want to cover the whole screen and you've got a VC inside of a UINavigationController, present it to the navigation controller.
  2. May be some issues with rotation (I didn't see any) on older iOS builds (4.0 or so)
  3. Currently only handles Cross Dissolve and Cover Vertical animations.
Inman answered 31/5, 2012 at 2:22 Comment(4)
Nice and tidy solution, thanks! Two observations though. First, notification's handler overViewDismissed releases self instead of the modal view controller and that leads to crash. Remove the notification code addObserver/postNotification altogether and manage modal view controller's memory outside present/dismiss methods. Second, [[UIScreen mainScreen] applicationFrame] does not always return the correct frame size. I use self.view.superview.frame instead (see this answer).Phenacaine
@VladimirGrigorov hey thanks for the note, it does seem to have some bad logic there. I don't remember which codebase I put this in, but imagine I fixed it locally... if you are still compiling / running a fixed version of it somewhere, could you edit the answer based on your findings? I could change it (is it just change [self autorelease] to [self.parentViewController autorelease] ? Risky for me to make the change blindly :)Inman
I have already removed the notification code as I stated in my previous comment and that version has passed testing...Phenacaine
There's also a this library that can do this: github.com/martinjuhasz/MJPopupViewControllerJunna
S
9

The answer for me was one line of code, added to the parent view controller before presenting the modal view controller:

self.modalPresentationStyle = UIModalPresentationCurrentContext;

This will stop the parent view from being removed once the modal view has been added.

Subequatorial answered 28/6, 2012 at 16:18 Comment(2)
But this works self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;Rhubarb
Did you set it on the parent view controller? And did you then use the command presentViewController:animated:completion:? I have to admit I have only tried this on iPad and not iPhone, but I don't see that would make a difference.Subequatorial
D
3

iOS doesn't support transparency when presenting a view modally.

Deka answered 16/2, 2011 at 13:53 Comment(2)
Yes I think. Till now iOS doesn't support transparency in modal. Thanks for your answer machunter. :)Sarita
well, knowing that does not help thoughDipole
D
0

Probably you want to add a UIView as an overlay to your current view but do it fullscreen with a transparent or semi-transparent background. See the first answer to this question:

disable elements on UIView behind modal UIView

Dortheydorthy answered 13/4, 2011 at 21:6 Comment(0)
D
0

You need to work it backwards, sort of. Load your modal view, then add all your elements on it "manually" as Subview, this way they wont be hidden behind. Yes, it is a lot of coding, but can be done. I did it for playing movies and having extra elements on the screen by setting smaller frame size for movie player and throwing some buttons and textviews around it as Subviews. B

Dipole answered 8/2, 2012 at 21:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.