在iPhone上将UIViewController显示为弹出窗口

75

鉴于这个常见的问题没有完整、确定的答案,我将在这里提出并回答。

通常,我们需要展示一个 UIViewController ,使其不覆盖整个屏幕,如下图所示。

enter image description here

苹果提供了几个类似的 UIViewController,例如 UIAlertView,Twitter 或 Facebook 分享视图控制器等。

我们如何为自定义控制器实现此效果?


10
请评论一下您为什么给出了负面评价,这样我才能改进。 - CRDave
我建议你使用STPopup,使用方法类似于UINavigationController。 - Kevin
我发现这个库很不错:https://github.com/huynguyencong/EzPopup - huync
8个回答

95

注意: 这个解决方案在iOS 8中已经失效了,我会尽快发布新的解决方案。

这里我将用storyboard来回答,但也可以不用storyboard实现。

  1. 初始化: 在storyboard中创建两个UIViewController

    • 假设一个是普通的FirstViewController,另一个是弹出窗口SecondViewController

  2. 模态Segue:FirstViewController中放置一个UIButton,并为此UIButton创建一个指向SecondViewController的模态Segue。

  3. 设置透明背景: 现在选择SecondViewControllerUIView(默认与UIViewController一起创建),将其背景颜色更改为透明色。

  4. 设置背景变暗:SecondViewController中添加一个UIImageView,覆盖整个屏幕,并将其图像设置为某种降低透明度的半透明图像。您可以从这里获取样本:UIAlertView背景图像

  5. 显示设计: 现在添加一个UIView,并制作任何想要展示的设计。这是我的storyboard的截图 storyboard

    • 在这里,我已经添加了登录按钮上的Segue,以弹出SecondViewController来请求用户名和密码。
  6. 重要提示: 现在是最关键的步骤。我们希望SecondViewController不完全遮挡FirstViewController。我们已经设置为透明色,但这还不够。默认情况下,在模态呈现后会添加黑色背景,因此我们必须在FirstViewControllerviewDidLoad中添加一行代码。您也可以在其他地方添加它,但应该在Segue之前运行。

    [self setModalPresentationStyle:UIModalPresentationCurrentContext];

  7. 取消显示: 何时取消显示取决于您的用例。由于这是模态呈现,因此我们执行模态呈现所需的操作即可取消显示:

    [self dismissViewControllerAnimated:YES completion:Nil];

就这些了.....

欢迎提出任何建议和评论。

演示 : 您可以从这里获取演示源代码:Popup Demo

新的: 某人在这个概念上做得非常好:MZFormSheetController
新的: 我找到了另一个代码来实现这种功能:KLCPopup


iOS 8更新:我使这种方法适用于iOS

+ (void)setPresentationStyleForSelfController:(UIViewController *)selfController presentingController:(UIViewController *)presentingController
{
    if (iOSVersion >= 8.0)
    {
        presentingController.providesPresentationContextTransitionStyle = YES;
        presentingController.definesPresentationContext = YES;

        [presentingController setModalPresentationStyle:UIModalPresentationOverCurrentContext];
    }
    else
    {
        [selfController setModalPresentationStyle:UIModalPresentationCurrentContext];
        [selfController.navigationController setModalPresentationStyle:UIModalPresentationCurrentContext];
    }
}
可以在prepareForSegue代理方法中像这样使用该方法。
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    PopUpViewController *popup = segue.destinationViewController;
    [self setPresentationStyleForSelfController:self presentingController:popup]
}

1
设置 [self setModalPresentationStyle:UIModalPresentationCurrentContext]; 似乎会破坏模态转换动画(例如 UIModalTransitionStyleCrossDissolve),当呈现第二个视图控制器时,它只是弹出而没有动画。有什么想法如何解决这个问题吗? - filwag
5
如您所建议的@CRDave,[self setModalPresentationStyle:UIModalPresentationCurrentContext];单独使用是无效的。必须像您演示项目中展示的那样同时使用[self.navigationController setModalPresentationStyle:UIModalPresentationCurrentContext]; - Vasu
@Kailash,你说得对,如果使用了navigationController,那么就需要它。我已经在这里写了:https://github.com/Chintan-Dave/popupDemo/issues/1。感谢你将其添加到这里。 - CRDave
如何更改弹出窗口的矩形? - Govind
在我的例子中,您可以在Storyboard中更改rect。 - CRDave
显示剩余9条评论

52

在Interface Builder(Storyboard)中创建模态弹窗

步骤1

在您要作为模态弹窗的视图控制器上,将根UIView的背景颜色设置为透明。 在根UIView上设置透明背景颜色 提示:不要使用根UIView作为您的弹窗。添加一个较小的新UIView来作为您的弹窗。

步骤2

创建一个Segue到拥有您的弹窗的视图控制器。选择“Present Modally”。 创建Segue

从这里开始创建弹窗的两种方法

方法一 - 使用Segue

选择Segue并将Presentation更改为“Over Current Context”: 选择Segue

方法二 - 使用视图控制器

选择您的弹窗所在的ViewController场景。在Attributes Inspector下,View Controller部分中,将Presentation设置为“Over Current Context”: 选择ViewController

任何一种方法都可以。就是这样!

完成的弹窗


如果需要,我可以提供更多帮助:在你的代码中创建一个视图控制器类,例如MyDialog:UIViewController。将它设置为故事板中新视图控制器的自定义类。添加按钮等控件,并使用“Control + Drag”将它们连接到你的代码中。在按钮点击事件中调用dismiss(animated, completion)。 - Numan Karaaslan
1
这太棒了。谢谢。 - Im Batman

13

你可以在Interface Builder中完成此操作。

  • 对于要以模态方式呈现的视图,请将其最外层视图背景设置为透明
  • 从主机视图控制器向模态视图控制器进行Control + 单击并拖动
  • 选择以模态方式呈现
  • 单击新创建的segue,在属性检查器(右侧)中将“Presentation”设置为“Over Current Context”

10

请放心使用我的表单表格控制器MZFormSheetController,在示例项目中有许多关于如何呈现模态视图控制器以不覆盖整个窗口并具有许多呈现/转换样式的示例。

您还可以尝试最新版本的MZFormSheetController,名为MZFormSheetPresentationController,它具有更多功能。


这个表单表格控制器看起来很棒,唯一的问题是当我呈现全屏模态视图控制器并且然后将其解除时,表单表格控制器也会变成全屏。请帮忙解决。 - Mazen Kasser
// 展示 MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithViewController:controller]; [formSheet presentAnimated:YES completionHandler:nil];// 关闭 MZFormSheetController *controller = self.navigationController.formSheetController; [controller dismissFormSheetControllerAnimated:YES completionHandler:nil]; - Mazen Kasser

2
您可以使用EzPopup(https://github.com/huynguyencong/EzPopup),它是一个Swift库,非常易于使用:
// init YourViewController
let contentVC = ...

// Init popup view controller with content is your content view controller
let popupVC = PopupViewController(contentController: contentVC, popupWidth: 100, popupHeight: 200)

// show it by call present(_ , animated:) method from a current UIViewController
present(popupVC, animated: true)

1

在背景上放置UIImageView不是最好的选择。在我的情况下,我在控制器视图上添加了另外两个视图。第一个视图背景使用[UIColor clearColor],第二个视图背景使用希望透明的颜色(在我的情况下是灰色)。请注意顺序很重要。然后为第二个视图设置alpha值为0.5(alpha值范围为0到1)。将这些行添加到prepareForSegue中。

infoVC.providesPresentationContextTransitionStyle = YES;
infoVC.definesPresentationContext = YES;

这就是全部。

1

Swift 4:

要添加覆盖层或弹出视图,您还可以使用容器视图,它提供了一个免费的视图控制器(您可以从常规对象调色板/库中获取容器视图)。

enter image description here

步骤:

  1. 创建一个包含此容器视图的视图(图片中的ViewForContainer),以在显示容器视图的内容时将其变暗。将outlet连接到第一个视图控制器内。

  2. 在第一个视图控制器加载时隐藏此视图。

  3. 当点击按钮时取消隐藏 enter image description here

  4. 为了在显示容器视图内容时将此视图变暗,将视图背景设置为黑色并将不透明度设置为30%。

enter image description here

当您点击按钮时,将会出现这种效果 在此输入图片描述

0

您可以这样做将任何其他子视图添加到视图控制器中。 首先,将要作为子视图添加的ViewController的状态栏设置为None,以便您可以将其调整为任何大小。然后在Present View Controller中创建一个按钮和一个用于按钮点击的方法。在该方法中:

- (IBAction)btnLogin:(id)sender {
    SubView *sub = [[SubView alloc] initWithNibName:@"SubView" bundle:nil];
    sub.view.frame = CGRectMake(20, 100, sub.view.frame.size.width, sub.view.frame.size.height);
    [self.view addSubview:sub.view];
}

希望这可以帮到你,如果有任何疑问,请随时提出...

这里的 SubView 是一个带有 xib 界面的 UIViewController,而不是一个子视图。 - User-1070892
好的,我之前不知道这种方法。谢谢。 - CRDave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接