导航控制器上的透明模态视图

时间:2009-05-11 18:40:57

标签: iphone

我正在尝试在导航控制器顶部创建透明模式视图。有谁知道这是否可行?

19 个答案:

答案 0 :(得分:109)

模态视图将覆盖它被推到顶部的视图以及导航控制器的导航栏。但是,如果你使用-presentModalViewController:animated:approach,那么一旦动画结束,刚刚覆盖的视图实际上会消失,这会使你的模态视图的任何透明度毫无意义。 (您可以通过在根视图控制器中实现-viewWillDisappear:和-viewDidDisappear:方法来验证这一点。)

您可以将模态视图直接添加到视图层次结构中,如下所示:

UIView *modalView =
    [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
modalView.opaque = NO;
modalView.backgroundColor =
    [[UIColor blackColor] colorWithAlphaComponent:0.5f];

UILabel *label = [[[UILabel alloc] init] autorelease];
label.text = @"Modal View";
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
[label sizeToFit];
[label setCenter:CGPointMake(modalView.frame.size.width / 2,
                                modalView.frame.size.height / 2)];
[modalView addSubview:label];

[self.view addSubview:modalView];

将modalView作为子视图添加到根视图中,这样实际上不会覆盖导航栏,但它将覆盖它下面的整个视图。我尝试使用用于初始化modalView的框架的原点,但负值导致它不显示。除了状态栏之外,我发现覆盖整个屏幕的最佳方法是将modalView添加为窗口本身的子视图:

TransparentModalViewAppDelegate *delegate = (TransparentModalViewAppDelegate *)[UIApplication sharedApplication].delegate;
[delegate.window addSubview:modalView];

答案 1 :(得分:18)

最简单的方法是使用 navigationController modalPresentationStyle 属性(但您必须自己制作动画):

self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalViewController animated:NO];
modalViewController.view.alpha = 0;
[UIView animateWithDuration:0.5 animations:^{
    modalViewController.view.alpha = 1;
}];

答案 2 :(得分:12)

我通过设置一个位于窗口或根视图的所有其他子视图上方的“OverlayViewController”来最轻松地实现此目的。在您的app委托或根视图控制器中进行设置,并使OverlayViewController成为单例,以便可以从代码中的任何位置或视图控制器层次结构访问它。然后,您可以随时调用方法来显示模态视图,显示活动指示器等,并且它们可以覆盖任何标签栏或导航控制器。

根视图控制器的示例代码:

- (void)viewDidLoad {
  OverlayViewController *o = [OverlayViewController sharedOverlayViewController];
  [self.view addSubview:o.view];
}

您可能用于显示模态视图的示例代码:

[[OverlayViewController sharedOverlayViewController] presentModalViewController:myModalViewController animated:YES];

我实际上并没有将-presentModalViewController:animated:与我的OverlayViewController一起使用,但我希望这可以正常工作。

另请参阅:What does your Objective-C singleton look like?

答案 3 :(得分:8)

我有同样的问题,为了解决方案是使用addSubview添加模态视图:并使用UIView的animateWithDuration:delay:options:animations:completion:

为视图层次结构中的更改添加动画效果

我在UIViewController(FRRViewController)的子类中添加了一个属性和2个方法,其中包含其他功能。我将很快在gitHub上发布所有内容,但在此之前你可以看到下面的相关代码。有关详细信息,请查看我的博客:How to display a transparent modal view controller

#pragma mark - Transparent Modal View
-(void) presentTransparentModalViewController: (UIViewController *) aViewController 
                                     animated: (BOOL) isAnimated 
                                    withAlpha: (CGFloat) anAlpha{

    self.transparentModalViewController = aViewController;
    UIView *view = aViewController.view;

    view.opaque = NO;
    view.alpha = anAlpha;
    [view.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        UIView *each = obj;
        each.opaque = NO;
        each.alpha = anAlpha;
    }];

    if (isAnimated) {
        //Animated
        CGRect mainrect = [[UIScreen mainScreen] bounds];
        CGRect newRect = CGRectMake(0, mainrect.size.height, mainrect.size.width, mainrect.size.height);


        [self.view addSubview:view];
        view.frame = newRect;

        [UIView animateWithDuration:0.8
                         animations:^{
                             view.frame = mainrect;
                         } completion:^(BOOL finished) {
                             //nop
                         }];

    }else{
        view.frame = [[UIScreen mainScreen] bounds];
        [self.view addSubview:view];
    }






}

-(void) dismissTransparentModalViewControllerAnimated:(BOOL) animated{

    if (animated) {
        CGRect mainrect = [[UIScreen mainScreen] bounds];
        CGRect newRect = CGRectMake(0, mainrect.size.height, mainrect.size.width, mainrect.size.height);
        [UIView animateWithDuration:0.8
                         animations:^{
                             self.transparentModalViewController.view.frame = newRect;
                         } completion:^(BOOL finished) {
                             [self.transparentModalViewController.view removeFromSuperview];
                             self.transparentModalViewController = nil;
                         }];
    }


}

答案 4 :(得分:7)

以下是我为解决问题所采取的措施 - Google的详细信息,但这种方法对我来说非常有用:

  • 截取基础视图的屏幕截图。 https://devforums.apple.com/message/266836 - 这会导致一个现成的方法,为当前屏幕返回一个UIView。
  • 将屏幕截图移至模态视图(我使用了属性)
  • 提出模态视图
  • 在模态视图控制器的viewDidAppear中,将图像设置为索引0处的UIImageView。按状态栏的高度调整图像的垂直位置。
  • 在模态视图控制器的viewWillDisappear中,再次删除图像

效果是:

  • 视图以任何模态视图的方式设置动画 - 模态视图的半透明部分滑过现有视图
  • 一旦动画停止,背景就会设置为屏幕截图 - 这使得它看起来好像旧视图仍在下面,即使它不是。
  • 一旦模态视图消失动画开始,图像就会被删除。操作系统同时显示旧的导航视图,因此模态视图可以透明地滑出,并且不会像您期望的那样在视线之外。

我尝试在自己的叠加视图中设置动画,但效果并不好。我得到了一次撞车,但没有迹象表明发生了什么事故。而不是追逐这个,我做了bg视图&工作得很好。

模态视图中的代码 - 我想你可以弄清楚其余部分,即设置属性modalView.bgImage ...

- (void)viewDidAppear:(BOOL)animated {
    // background
    // Get status bar frame dimensions
    CGRect statusBarRect = [[UIApplication sharedApplication] statusBarFrame];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:self.bgImage];
    imageView.tag = 5;
    imageView.center = CGPointMake(imageView.center.x, imageView.center.y - statusBarRect.size.height);
    [self.view insertSubview:imageView atIndex:0];
}

- (void)viewWillDisappear:(BOOL)animated {
    [[self.view viewWithTag:5] removeFromSuperview];
}

答案 5 :(得分:4)

如果您将模态视图控制器的modalPresentationStyle设置为:

viewController.modalPresentationStyle = 17;

不删除后台视图。 (TWTweetComposeViewController使用它)。

我没有尝试使用此代码通过App Store审核

答案 6 :(得分:4)

self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:newview animated:YES];

并确保将模态视图背景设置为透明,

self.view.background = .... alpha:0.x;

答案 7 :(得分:3)

关于displaying a semi-transparent "Loading..." view的这篇文章可能会就如何继续提供一些指示。

答案 8 :(得分:3)

是的,您必须手动添加视图,如果您想从底部滑入,或者您也需要自己动手制作动画。

我写了一个类来做这个,以及一个使用该类作为示例的半模式日期选择器。

您可以在this blog post中找到文档,代码为on github

答案 9 :(得分:2)

我从https://gist.github.com/1279713

得到了这个想法

<强>准备: 在模态视图xib(或使用故事板的场景)中,我设置了全屏幕背景UIImageView(用.h文件钩住它并给它一个属性“backgroundImageView”)0.3 alpha。我将视图(UIView)背景颜色设置为纯黑色。

<强>思想: 然后在模态视图控制器的“viewDidLoad”中,我从原始状态捕获屏幕截图并将该图像设置为背景UIImageView。将初始Y点设置为-480,并使用EaseInOut动画选项使用0.4秒的持续时间将其滑动到Y点0。当我们关闭视图控制器时,只需做相反的事情。

模态视图控制器类的代码

.h文件:

@property (weak, nonatomic) IBOutlet UIImageView *backgroundImageView;
- (void) backgroundInitialize;
- (void) backgroundAnimateIn;
- (void) backgroundAnimateOut;

.m文件:

- (void) backgroundInitialize{
    UIGraphicsBeginImageContextWithOptions(((UIViewController *)delegate).view.window.frame.size, YES, 0.0);
    [((UIViewController *)delegate).view.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * screenshot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    backgroundImageView.image=screenshot;
}
- (void) backgroundAnimateIn{
    CGRect backgroundImageViewRect = backgroundImageView.frame;
    CGRect backgroundImageViewRectTemp = backgroundImageViewRect;
    backgroundImageViewRectTemp.origin.y=-480;
    backgroundImageView.frame=backgroundImageViewRectTemp;

    [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^{
        backgroundImageView.frame=backgroundImageViewRect;
    } completion:^(BOOL finished) {

    }];
}
- (void) backgroundAnimateOut{
    CGRect backgroundImageViewRect = backgroundImageView.frame;
    backgroundImageViewRect.origin.y-=480;

    [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^{
        backgroundImageView.frame=backgroundImageViewRect;
    } completion:^(BOOL finished) {

    }];
}

在viewDidLoad中,只需调用:

[self backgroundInitialize];
[self backgroundAnimateIn];

在我们解雇模态视图控制器的任何地方,我们都会调用:

[self backgroundAnimateOut];

请注意,这将始终为背景图像设置动画。因此,如果此模态视图控制器转换样式(或segue过渡样式)未设置为“Cover Vertical”,则可能不需要调用动画方法。

答案 10 :(得分:2)

过去一周我一直在研究同样的问题。我尝试了谷歌和StackOverflow上的所有各种答案和示例。他们都没有那么好。

刚接触iOS编程时,我不知道名为UIActionSheet的内容。因此,如果您要尝试完成此操作以显示按钮的模式叠加(例如模式询问某人他们想要如何分享某些内容),请使用UIActionSheet

这是a webpage that shows an example of how to do this

答案 11 :(得分:2)

我终于完成了这个,对于导航或标签栏界面,通过组合覆盖视图控制器(请参阅:pix0r的答案)隐藏/未隐藏,然后隐藏或显示基于此非常好的视图控制器{{3} }。

关于视图控制器,提示是使其背景视图为clearColor,然后半透明叠加视图可见,并且视图控制器中的子视图位于前面且最重要的是不透明时添加任何视图

答案 12 :(得分:1)

我已经创建了open soruce库MZFormSheetController来在其他UIWindow上呈现模态表单。您可以使用它来呈现透明模态视图控制器,甚至可以调整显示的视图控制器的大小。

答案 13 :(得分:1)

对于iOS 8+,您可以对呈现的视图控制器使用UIModalPresentationOverCurrentContext演示文稿样式,以轻松实现所需的行为。

UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.9f];
viewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:viewController animated:YES completion:nil];

如果您还需要支持iOS 7 - 请检查this thread

答案 14 :(得分:0)

您可以通过在视图和导航栏上覆盖透明/半透明按钮来实现透明/半透明模态视图效果。

您可以通过UINavigationController的navigationBar属性访问导航栏。

我发现与UILabel不同的UIButton会捕获鼠标事件 - 从而给出正确的模态行为。

答案 15 :(得分:0)

我刚刚找到了解决方法。只需创建1X1的UIViewController并将其添加到父视图控制器。并在UIViewController中显示透明模态视图控制器。

on viewDidLoad;

  

self.dummyViewController = [[UIViewController alloc] init];   [self.dummyViewController.view setFrame:CGRectMake(0,0,1,1)];   [self.view addSubView:self.dummyViewController.view];

当你需要打开transparentViewController时;

  

[self.dummyViewController presentModalViewController:yourTransparentModalViewController animated:true];

答案 16 :(得分:0)

如果您需要一个类似附加屏幕的屏幕,以下代码可能会对您有所帮助。enter image description here

代码:

MyViewController * myViewController = [[MyViewController alloc] initWithNibName:nibName bundle:nil];
UINavigationController * myNavigationController = [[UINavigationController alloc] initWithRootViewController: myViewController];
myNavigationController.modalPresentationStyle = UIModalPresentationPageSheet;
[self presentModalViewController: myNavigationController animated:YES];

答案 17 :(得分:0)

如果你想要一个屏幕叠加,请使用parentViewController.view,它将放在导航栏上方++

MyCustomViewController* myOverlayView = [[MyCustomViewController alloc] init]; [self.parentViewController.view addSubview:myOverlayView];

答案 18 :(得分:0)

这对我有用:

UIViewController *modalViewController = [[UIViewController alloc] init];
modalViewController.view.backgroundColor = [UIColor whiteColor] colorWithAlpha:0.5];
[self showDetailViewController:modalViewController sender:nil];