iOS - Semi-transparent modal view controller

2019-02-02 05:05发布

问题:

I want to present a view controller with a slightly transparent background modally over the current view, such that the first view is slightly visible under the modal view.

I set the alpha value of the modal view controller and set the modalPresentationStyle to UIModalPresentationCurrentContext, as suggested in another post.

The result is that the view background is transparent when animating up, but when view controller is in place it changes to opaque black. It goes back to being transparent while animating the dismissal.

How can I get it to be transparent when active ?

I have tested in iOS 6 and 7. The code I am using follows:

MyModalViewController *viewController = [[MyModalViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navController setNavigationBarHidden:YES];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self.navigationController presentViewController:navController animated:YES completion:NULL];

回答1:

iOS 8 added a new modal presentation style specifically for this purpose:

presentedViewController.modalPresentationStyle = UIModalPresentationOverFullScreen

From the spec:

UIModalPresentationOverFullScreen

A view presentation style in which the presented view covers the screen. 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.



回答2:

If you are targeting ios 8 and above you can set the modal presentation style to "over current context" and you are done. If ios 7 and below, you would have to create a custom transition style so that the presenting screen doesn't go blank after transition. That is rather complicated.

The solution I present offers a lot of flexibility: make a screenshot before showing the modal dialog and set that as the background image for the application window. By default, that background is black (that is what you see when the back view controller dissapears). Change the background to the screenshot of the app. Make the screenshot in the viewWillAppear or viewDidLoad method of your transparent view. This works even with push segues, not only modal dialogs, but you should avoid animations. In general, avoid animations which affect the position of the background view because those will make it seem like it snaps back into place when transition finishes. It is a good idea to reset the background to its previous black image on viewDidDissapear to avoid unwanted effects.

You can maintain a stack of such background images and you can do multiple "transparent" push seques. Or have some complex/deep menu which appears on top of some main screen. For these many reasons I think this solution is better than rolling your own transitioning code. It is more flexible and easier to implement, and you don't have to deal with the animations yourself.



回答3:

The reason that the BG view controllers disappear after a modal is shown is that the default transition in iOS 7 removes the BG view after animation completed. If you define your own transition and you set your BG view not to be removed (just changing its alpha) then you will have the transparent modal view.



回答4:

Here is a solution.

Create your presenting view controller. Add a backView to this view controller's main view. Name this as backView.

In SecondViewController.m

-(void)viewDidLoad
{
    // Make the main view's background clear, the second view's background transparent.
    self.view.backgroundColor = [UIColor clearColor];
    UIView* backView = [[UIView alloc] initWithFrame:self.view.frame];
    backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
    [self.view addSubview:backView];
}

Now you have a view controller with half transparent background. You can add anything you want to the self.view , the rest will be half transparent.

After that, in FirstViewController.m

self.modalPresentationStyle = UIModalPresentationCurrentContext;

[self presentViewController:secondViewController animated:YES completion:nil];


回答5:

My solution is this:

Create a custom transparent overlay UIView that comes over any view, navigationbar and tabbbar.

-In the navigation controller (or tabbar controller) that your view controller is embedded in I create a custom view with it's frame equal to the frame of the navigation controller's view.

-Then I set it offscreen by setting it's origin.y to navigationController.view.height

-Then I create 2 functions -(void)showOverlay and -(void)hideOverlay that animate the overlay view on and off screen:

- (void)hideOverlay{
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.3];

    CGRect frm = self.helpView.frame;//helpView is my overlay
    frm.origin.y = self.offscreenOffset; //this is an Y offscreen usually self.view.height
    self.helpView.frame = frm;

    [UIView commitAnimations];
}

- (void)showOverlay{

    [self.view bringSubviewToFront:self.helpView];

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.3];

    CGRect frm = self.helpView.frame;
    frm.origin.y = self.onscreenOffset;
    self.helpView.frame = frm;

    [UIView commitAnimations];
}

-In my view controller I can just call

[(MyCustomNavCtrl *)self.navigationController showOverlay];
[(MyCustomNavCtrl *)self.navigationController hideOverlay];

And that's about it.



回答6:

FYI: The syntax is now:

    childVC.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen


回答7:

Same problem occured to me. I have solved it by looking at the following url about a custom alert controller. I managed to get it working even with a UINavigationController.

Swift 4

let viewController = UIViewController()
viewController.providesPresentationContextTransitionStyle = true
viewController.definesPresentationContext = true
viewController.modalPresentationStyle = .overCurrentContext
viewController.modalTransitionStyle = .crossDissolve
DispatchQueue.main.async {
    self.navigationController?.present(viewController, animated: true, completion: nil)
}


回答8:

Why don't you try setting this in AppDelegate

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

then changing the alpha on the view being presented