【发布时间】:2010-10-25 08:50:44
【问题描述】:
我正在尝试在我的导航控制器上创建一个透明的模态视图。有谁知道这是否可能?
【问题讨论】:
-
注意:对于 2014 年,一个绝对的解决方案就是使用容器视图,全屏 - 然后你就拥有绝对的、完全的控制权,并且可以做任何你想做的事情(动画,滑动它 - 任何东西)。在某些情况下,这是最好的解决方案。
标签: iphone
我正在尝试在我的导航控制器上创建一个透明的模态视图。有谁知道这是否可能?
【问题讨论】:
标签: iphone
我通过设置位于我的窗口或根视图的所有其他子视图之上的“OverlayViewController”来最轻松地完成此操作。在您的应用程序委托或根视图控制器中进行设置,并使 OverlayViewController 成为单例,以便可以从代码或视图控制器层次结构中的任何位置访问它。然后,您可以在需要时调用方法来显示模式视图、显示活动指示器等,它们可能会覆盖任何标签栏或导航控制器。
根视图控制器的示例代码:
- (void)viewDidLoad {
OverlayViewController *o = [OverlayViewController sharedOverlayViewController];
[self.view addSubview:o.view];
}
您可以用来显示模态视图的示例代码:
[[OverlayViewController sharedOverlayViewController] presentModalViewController:myModalViewController animated:YES];
我实际上并没有将-presentModalViewController:animated: 与我的 OverlayViewController 一起使用,但我希望这会正常工作。
【讨论】:
模态视图将覆盖它被推送到顶部的视图以及导航控制器的导航栏。但是,如果您使用 -presentModalViewController:animated: 方法,那么一旦动画完成,刚刚覆盖的视图实际上会消失,这会使您的模态视图的任何透明度变得毫无意义。 (您可以通过在根视图控制器中实现 -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];
【讨论】:
这篇关于displaying a semi-transparent "Loading..." view 的帖子可能会就如何进行提供一些指导。
【讨论】:
您可以通过在视图和导航栏上叠加一个透明/半透明按钮来实现透明/半透明模态视图效果。
您可以通过 UINavigationController 的 navigationBar 属性访问导航栏。
我发现 UIButton 与 UILabel 不同,它会捕获鼠标事件——因此会给出正确的模态行为。
【讨论】:
对于导航或标签栏界面,我终于实现了这一点,方法是结合一个覆盖视图控制器(参见:pix0r 的答案),该控制器在隐藏或显示基于这个非常好的 blog post 的视图控制器之前隐藏/取消隐藏。
关于视图控制器,提示是将其背景视图设置为clearColor,然后半透明覆盖视图可见,并且在视图控制器中作为子视图添加的任何视图都在前面,最重要的是不透明。
【讨论】:
是的,你必须手动添加视图,如果你想从底部滑入或者你必须自己做动画。
我编写了一个类来执行此操作,并使用该类作为示例的半模态日期选择器。
你可以在this blog post找到文档,代码是on github
【讨论】:
我遇到了同样的问题,为了解决这个问题,解决方案是使用 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;
}];
}
}
【讨论】:
过去一周我一直在研究同样的问题。我尝试了在 Google 和 StackOverflow 上找到的所有各种答案和示例。它们都没有那么好用。
作为 iOS 编程新手,我不知道名为 UIActionSheet 的东西。因此,如果您尝试完成此操作以显示按钮的模态覆盖(例如模态询问某人他们想如何共享某些内容),只需使用UIActionSheet。
【讨论】:
这是我为解决问题所做的 - 谷歌详细信息,但这种方法对我来说非常有效:
效果是:
我尝试在自己的叠加视图中制作动画,但效果不佳。我遇到了崩溃,没有任何迹象表明发生了什么崩溃。我没有追究这一点,而是做了 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];
}
【讨论】:
我从https://gist.github.com/1279713得到这个想法
准备: 在模态视图 xib(或使用情节提要的场景)中,我设置了 0.3 alpha 的全屏背景 UIImageView(将其与 .h 文件挂钩并为其赋予属性“backgroundImageView”)。我将视图 (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”,你可能不需要调用动画方法。
【讨论】:
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:newview animated:YES];
并确保将模态视图背景设置为透明,
self.view.background = .... alpha:0.x;
【讨论】:
最简单的方法是使用 navigationController 的 modalPresentationStyle 属性(但您必须自己制作动画):
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalViewController animated:NO];
modalViewController.view.alpha = 0;
[UIView animateWithDuration:0.5 animations:^{
modalViewController.view.alpha = 1;
}];
【讨论】:
presentModalViewController 切换为 presentViewController。
如果您将模态视图控制器的 modalPresentationStyle 设置为:
viewController.modalPresentationStyle = 17;
后台的视图不会被移除。 (TWTweetComposeViewController 使用它)。
我并没有尝试使用此代码通过 App Store 审核
【讨论】:
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; 更改为 controller.modalPresentationStyle = 17;
我刚刚找到了解决方法。只需创建一个 1X1 的 UIViewController 并将其添加到您的父视图控制器。并在那个 UIViewController 中显示透明的模态视图控制器。
在 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];
【讨论】:
我创建了开放源库MZFormSheetController 以在其他 UIWindow 上显示模式表单。您可以使用它来呈现透明度模态视图控制器,甚至可以调整呈现的视图控制器的大小。
【讨论】:
如果你需要一个类似附件的屏幕,下面的代码可以帮助你。
代码:
MyViewController * myViewController = [[MyViewController alloc] initWithNibName:nibName bundle:nil];
UINavigationController * myNavigationController = [[UINavigationController alloc] initWithRootViewController: myViewController];
myNavigationController.modalPresentationStyle = UIModalPresentationPageSheet;
[self presentModalViewController: myNavigationController animated:YES];
【讨论】:
如果说你想要一个屏幕覆盖,使用 parentViewController.view,它会放在导航栏上方 ++
MyCustomViewController* myOverlayView = [[MyCustomViewController alloc] init];
[self.parentViewController.view addSubview:myOverlayView];
【讨论】:
这对我有用:
UIViewController *modalViewController = [[UIViewController alloc] init];
modalViewController.view.backgroundColor = [UIColor whiteColor] colorWithAlpha:0.5];
[self showDetailViewController:modalViewController sender:nil];
【讨论】:
对于 iOS 8+,您可以为 presented 视图控制器使用 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。
【讨论】: