【问题标题】:present modal form sheet over modal page sheet在模态页面表上显示模态表单
【发布时间】:2012-04-11 11:08:33
【问题描述】:

在 iPad 上,我使用 modalPresentationStyle UIModalPresentationPageSheet 显示模态视图控制器。此视图控制器使用 modalPresentationStyle UIModalPresentationFormSheet 呈现另一个模态视图控制器。

因此,用户看到背景视图控制器、页面表单和表单表单都在彼此的顶部,因为表单表单比页面表单小。页面表的呈现使背景变暗,因此无法与之交互。但是,表单不会在 iOS 5 上使页面表变暗,因此用户仍然可以与下面的页面表进行交互。但我也希望页面变暗,以便用户在再次与页面交互之前关闭模式表单。

在 iOS 4 上,这是默认行为,但在 iOS 5 上,我找不到实现此目的的方法。你有什么建议吗?

【问题讨论】:

  • 我在 iOS 5 中注意到了这一点,并在 iOS 6 中看到了同样的问题。
  • 我刚刚将此作为错误报告 12540692 提交。

标签: ios ipad uikit modalviewcontroller


【解决方案1】:

我认为这是 iOS5 中的一个错误。我已经做了一些从其他模态呈现模态视图控制器的实验,似乎第二个模态永远不会使下面的屏幕变暗。我什至设置了一个测试项目,允许您彼此启动无尽的模态,并且似乎每个其他模态都没有像预期的那样变暗或阻止触摸。

UIWindow 子视图上的快速 NSLog 告诉我们,虽然适当地添加了阴影,但 dimmingView 没有。我正在研究一种方法来展示我自己的调光视图。找到方法后会更新此答案。

Window Subviews: (
    "<UILayoutContainerView: 0xf63e3c0; frame = (0 0; 768 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0xf645640>>",
    "<UIDimmingView: 0xf683990; frame = (0 0; 768 1024); opaque = NO; layer = <CALayer: 0xf6836d0>>",
    "<UIDropShadowView: 0xf683130; frame = (64 64; 640 896); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0xf6831c0>>",
    "<UIDropShadowView: 0x292110; frame = (74 242; 620 540); transform = [0, 1, -1, 0, 0, 0]; autoresize = LM+RM+TM+BM; layer = <CALayer: 0x292150>>"
)

解决方案二: 所以在我的动画外观的最终解决方案中。 我还开始考虑我的第一个解决方案,它在技术上可能会激怒 Apple 并导致拒绝,因为 UIDimmingView 没有记录,我们“触摸它”。我添加了一个背景颜色为 alpha 的 UIView我们想要我的viewController。然后我在呈现模态时对其进行动画处理,并在调用第二个模态的委托时反转动画。对我来说看起来很不错。可能会进行一些时间和 alpha 调整以使其恰到好处,但它可以正常工作并且看起来不错。

- (void)viewDidLoad 
{
    dim = [[UIView alloc] init];
    [dim setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.35]];
    [dim setAlpha:0.0];
    [dim setUserInteractionEnabled:NO];
    [self.view addSubview:dim];
}

- (void)presentModal
{
    [self.view bringSubviewToFront:dim];
    [dim setFrame:self.view.frame];
    [UIView animateWithDuration:0.25 animations:^{
        [dim setAlpha:1.0];
    }];
}

- (void)modalDelegateFinished
{
    [UIView animateWithDuration:0.25 animations:^{
        [dim setAlpha:0.0];
    }];
}

解决方案一:

好吧,这可行,但它没有我想要的动画效果。然而,它确实重用了已经存在的东西,所以这可能是一个加分项。

- (void)viewDidAppear:(BOOL)animated
{
    // Add a gesture to dismiss the view if tapped outside.
    UIGesture *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedOutsideView:)];
    [gesture setNumberOfTapsRequired:1];
    [gesture setCancelsTouchesInView:NO];
    [self.view.window addGestureRecognizer:gesture];

    // Move the dimmingview to just below the dropshadow.
    UIView *dim = [self.view.window.subviews objectAtIndex:1];
    [self.view.window insertSubview:dim atIndex:2];
}

- (void)tappedOutsideView:(UITapGestureRecognizer *)sender
{
    if (sender.state == UIGestureRecognizerStateEnded) {
        CGPoint location = [sender locationInView:nil];

        if (![self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil]) {
            // remove the gesture on the window
            [self.view.window removeGestureRecognizer:sender];

            // Move the dimmingview back where it belongs
            UIView *dim = [self.view.window.subviews objectAtIndex:2];
            [self.view.window insertSubview:dim atIndex:1];
        }
    }
}

同样作为故障保护,它对于 viewDidDisappear 中的相同内容可能是一个好主意。我的完成按钮调用了 tappedOutside 视图,所以我知道手势和 dimmingView 总是正确的。但如果你不这样做,你可以把它放在 viewDidDisappear 中。

- (void)viewDidDisappear:(BOOL)animated
{
    // remove the gesture on the window
    for (UIGestureRecognizer *gesture in self.view.window.gestureRecognizers) {
        [self.view.window removeGestureRecognizer:gesture];
    }

    // Move the dimmingview back where it belongs
    UIView *dim = [self.view.window.subviews objectAtIndex:2];
    [self.view.window insertSubview:dim atIndex:1];
}

【讨论】:

  • 这是我的经验。现在我只是不在页面顶部显示表单,而是在我的应用程序中的任何地方使用页面表。
  • 我已经设置了窗口手势,所以在模态框外点击总是会导致它关闭。因此,由于触摸无法通过我的手势,它们可以通过背景模式。然而在视觉上它会变暗很好。我可能会在一个系统上工作,以使窗口中除模式之外的所有内容都变暗。
  • 更新了我的答案。我找到了两种解决方案。一个比另一个更生动和安全。 :)
  • 感谢您对这个问题的实验!我认为解决方案二更好,因为它是动画的并且不会与 iOS 的视图混淆。这个解决方案仍然可以改进,所以不是呈现视图控制器自己变暗,而是模态视图控制器使呈现视图控制器变暗。不过,我不知道这是否可能。
  • 除此之外,我仍然认为这是iOS5中的一个错误。如果您在其他模式视图控制器之上呈现第三个模式视图控制器,则背景再次变暗。因此,iOS 中发生了一些非常奇怪的事情。
【解决方案2】:

这看起来确实是一个 iOS 错误。在 iOS7 中仍然存在。

这是我为解决它所做的工作(iOS7 测试)。有趣的是,在模态上呈现模态不会使演示者变暗,但在它们之上呈现的第三个模态会。

知道了这一点,我们可以在展示实际的表单模式之前​​展示一个虚拟模型。这涉及最少的代码,并且在技术上符合一般的 iOS 设计模式。所以未来爆炸的风险应该是最小的。

首先展示表单:

- (void)presentFormSheetModalOverThePageSheetModal
{
    //get the controller I'm trying to present and stick it in a nav controller - as usual
    UIViewController *myModalController = [UIViewController new];
    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:myModalController];
    navController.modalPresentationStyle = UIModalPresentationFormSheet;

    //create an intermediate controller that will be presented first
    UIViewController *intermediateController = [UIViewController new];
    intermediateController.modalPresentationStyle = UIModalPresentationCurrentContext;
    intermediateController.view.backgroundColor = self.view.backgroundColor;

    //create a snapshot of self (presenting controller)
    UIView *navBar = [self.navigationController.navigationBar snapshotViewAfterScreenUpdates:YES];
    UIView *mainView = [self.view snapshotViewAfterScreenUpdates:YES];
    mainView.center = CGPointMake(mainView.center.x, mainView.center.y + navBar.frame.size.height);
    [intermediateController.view addSubview:navBar];
    [intermediateController.view addSubview:mainView];

    //two step presentation
    [self presentViewController:intermediateController animated:NO completion:^{
        [intermediateController presentViewController:navController animated:YES completion:nil];
    }];
}

然后是时候关闭(从呈现的模式):

- (void)dismissMySelf
{
    //again - two step process to dismiss the this controller and the intermediate controller
    UIViewController *originalPresenter = self.presentingViewController.presentingViewController;
    [self.presentingViewController dismissViewControllerAnimated:YES completion:^{
        [originalPresenter dismissViewControllerAnimated:NO completion:nil];
    }];
}

我不得不调整它,因为快照是静态图像并且不处理旋转,但总的来说它对我来说效果很好。希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 2020-01-20
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多