带有 ModalPresentationStyle 的弹出框不在 iOS 7 iPad 中居中

Posted

技术标签:

【中文标题】带有 ModalPresentationStyle 的弹出框不在 iOS 7 iPad 中居中【英文标题】:Popover with ModalPresentationStyle is not centered in iOS 7 iPad 【发布时间】:2013-09-22 04:45:59 【问题描述】:

我在使用 ios 7 时遇到了一个问题,这似乎是一个错误,或者我没有做正确的事情。我有 modalViewController,它在 iPad 上显示为带有 ModalPresentationStyle 的弹出框。而且它不是标准尺寸,定制尺寸。 代码如下:

myViewController *myVC = [[myViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:myVC];
[nav setModalPresentationStyle:UIModalPresentationFormSheet];
[nav setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal];
[self presentViewController:nav animated:YES completion:nil];
nav.view.superview.bounds = CGRectMake(0, 0, 320, 465);

在 iOS 6 中一切正常,但在 iOS 7 中它没有居中。 但是,如果我将 ModalTransitionStyle 设置为 UIModalTransitionStyleCrossDissolve 它工作正常。但仅限于这种模式。 也许有人也偶然发现了这个并且知道如何解决它?我不是溶解效果的忠实粉丝。 谢谢。

【问题讨论】:

【参考方案1】:

我遇到了同样的问题。我已经通过使用另一种方法解决了这个问题,发现 here。

这个方案提出的是使用(void)viewWillLayoutSubviews的方法

所以如果@Manuel M. 在GeneralSettingsViewController 内添加以下代码:

// GeneralSettingsViewController
- (void)viewWillLayoutSubviews
    [super viewWillLayoutSubviews];
    self.view.superview.bounds = CGRectMake(0, 0, 497, 375);

您将不再需要此代码:

self.generalSettingsVC.view.superview.frame = CGRectMake(0, 0, 497, 375);
self.generalSettingsVC.view.superview.center = self.view.center;

对于@titicaca,您使用的是UINavigationController,我尚未使用此控制器对其进行测试,但您可以尝试我提到的相同解决方案,扩展UINavigationController 并覆盖viewWillLayoutSubviews 方法。

[编辑]

对于@titicaca,我在一个新项目中进行了尝试,对我来说它有效。我所做的是有一个自定义导航视图控制器CustomNavigationController 覆盖viewWillLayoutSubviews,如下所示:

- (void)viewWillLayoutSubviews
    [super viewWillLayoutSubviews];
    self.view.superview.bounds = CGRectMake(0, 0, 330, 284);

然后,呈现CustomNavigationController 的视图控制器应该执行类似于以下的代码:

UIViewController *myVC = [[UIViewController alloc] init];
[myVC.view setBackgroundColor:[UIColor redColor]];

CustomNavigationController *nav = [[CustomNavigationController alloc] initWithRootViewController:myVC];
[nav setModalPresentationStyle:UIModalPresentationFormSheet];
[nav setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal];

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

您需要确保self.view.superview.bounds = CGRectMake(0, 0, 330, 284); 的尺寸是偶数,否则里面的文字会变得模糊,如果有的话

【讨论】:

我想知道是否有人可以解释为什么 a) 必须调用 view.superview.bounds 属性才能解决此问题,以及 b) 如何为矩形的原点传入 (0,0) 导致它居中? 我发现viewWillAppear: 是放置self.view.superview.bounds=xxx 的更好位置,因为它比viewWillLayoutSubviews 更早被调用【参考方案2】:

对我来说,问题是在呈现的视图控制器的 viewDidAppear 中的文本字段上调用 ​​becomeFirstResponder。现在似乎是一个错误。解决方案是将其包装在一个简单的dispatch_async

- (void)viewDidAppear:(BOOL)animated

    [super viewDidAppear:animated];
    dispatch_async(dispatch_get_main_queue(), ^
        [self.userNameTextField becomeFirstResponder];
    );

【讨论】:

【参考方案3】:

对我来说也是一样...我还不知道如何解决它。我目前正在处理这个问题,所以我会分享任何我得到的东西!

这是我的代码。

-(IBAction)showGeneralSettings:(id)sender

self.generalSettingsVC = [[GeneralSettingsViewController alloc] initWithNibName:@"GeneralSettingsView" bundle:nil];

//Present the view controller as a modal with a custom size (important to do after presenting it)
self.generalSettingsVC.modalPresentationStyle = UIModalPresentationFormSheet;

[self presentViewController:self.generalSettingsVC animated:YES completion:nil];

self.generalSettingsVC.view.superview.frame = CGRectMake(0, 0, 497, 375);
self.generalSettingsVC.view.superview.center = self.view.center;

【讨论】:

嘿曼努埃尔,你找到解决办法了吗? 嘿! @Tamara Bernad 的解决方案非常有效。尝试一下。我不能投票得那么好,因为我还没有名声:( 不幸的是,它对我没有那么好。它将弹出框放在中心,但它不是我的尺寸,它只是标准尺寸的弹出框窗口,我的东西也居中..【参考方案4】:

我有一个方法,旧的自定义模式演示样式fromsheetiOS <=7 一起使用,尽管您可以设置custom height and width

请记住,此方法可能不适用于将来的任何新版本

- (void) hackModalSheetSize:(CGSize) aSize ofVC:(UIViewController *) aController;


    void (^formSheetBlock) (void) = ^
        int preferredWidth = aSize.width;
        int preferredHeight = aSize.height;

        CGRect frame = CGRectMake((int) 1024/2 - preferredWidth/2,
                                  (int) 768/2 - preferredHeight/2,
                                  preferredWidth, preferredHeight);
        aController.view.superview.frame = frame;
        if([aController respondsToSelector:@selector(edgesForExtendedLayout)])  //ios7
            aController.view.superview.backgroundColor = [UIColor clearColor];
         else  // < ios7
            UIImageView *backgroundView = [aController.view.superview.subviews objectAtIndex:0];
            [backgroundView removeFromSuperview];
        
    ;

    //on ios < 7 the animation would be not as smooth as on the older versions so do it immediately
    if(![self respondsToSelector:@selector(edgesForExtendedLayout)]) 
        formSheetBlock();
        return;
    

    double delayInSeconds = .05;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

    dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
        formSheetBlock();
    );

【讨论】:

我会接受这个答案,因为这对我有用,至少现在是这样。虽然我最终使用了 MZFormSheetController——它确实是一个很棒的 ios 7 风格的解决方案,在两个 ios 版本中都适用于我。虽然我真的很想在未来弄清楚如何使用原生 ios 套件来处理这个问题,但现在似乎是一个错误。 嘿,它不起作用,它只是显示弹出窗口,然后再次进入表单中的完整视图。任何想法***.com/questions/30615075/…【参考方案5】:

上面的解决方案对我不起作用。我使用了以下内容:

      UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:theViewController];
      navigationController.modalPresentationStyle=UIModalPresentationFormSheet;
      [self presentViewController:navigationController animated:YES completion:nil];
      if([[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPhone)
            navigationController.view.superview.frame = CGRectMake(0, 0, 320, 544);
            navigationController.view.frame =CGRectMake(108, 0, 320, 544);
            navigationController.view.superview.backgroundColor=[UIColor clearColor];
      

【讨论】:

【参考方案6】:

我在 Swift 中使用子类导航控制器和 AutoLayout 进行了稍微不同的处理,以将超级视图中的视图以设定的宽度和高度居中。我的特殊情况需要 iPad 和 iOS7-8 支持(这段代码中有一些特定于我的项目的常量,但你明白了)...

class CenteredModalNavigationController: UINavigationController 

    // MARK:- Methods

    override func viewDidLoad() 
        super.viewDidLoad()
        preferredContentSize = CGSizeMake(320, 480) // iOS8 only
    

    override func viewWillAppear(animated: Bool) 
        super.viewWillAppear(animated)

        // iOS7 support for iPad custom sized form-sheet modal.
        if kDeviceiOS7 && kDeviceiPad 
            if view.superview == nil 
                Log.warning("Failed to find superview")
                return
            
            view.superview!.setTranslatesAutoresizingMaskIntoConstraints(false)

            // Give the superview constraints to center the view inside it.
            var viewBindingsDict: NSMutableDictionary = NSMutableDictionary()
            viewBindingsDict.setValue(view, forKey: "view")
            viewBindingsDict.setValue(view.superview!, forKey: "superview")
            let centerXConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:[superview]-(<=1)-[view]",
                options: .AlignAllCenterX,
                metrics: nil,
                views: viewBindingsDict)
            view.superview!.addConstraints(centerXConstraints)

            let centerYConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:[superview]-(<=1)-[view]",
                options: .AlignAllCenterY,
                metrics: nil,
                views: viewBindingsDict)
            view.superview!.addConstraints(centerYConstraints)

            // Now give it a width/height and it should float in the middle of our superview.
            AutoLayoutHelper.addWidthConstraint(view,
                aSuperView: view.superview!,
                width: 320)
            AutoLayoutHelper.addHeightConstraint(view,
                aSuperView: view.superview!,
                height: 480)
        
    

    override func prefersStatusBarHidden() -> Bool 
        return true
    

    override func disablesAutomaticKeyboardDismissal() -> Bool 
        // DEVNOTE: Because this is shown in a modal, this is required to stop keyboard dismiss issues.
        return true
    


...

class AutoLayoutHelper: NSObject 

    class func addHeightConstraint(aChildView:UIView, aSuperView:UIView, height:CGFloat) 
        var constraint = NSLayoutConstraint(item: aChildView,
            attribute: NSLayoutAttribute.Height,
            relatedBy: NSLayoutRelation.Equal,
            toItem: nil,
            attribute: NSLayoutAttribute.NotAnAttribute,
            multiplier: 1.0,
            constant: height)
        aSuperView.addConstraint(constraint)
    

    class func addWidthConstraint(aChildView:UIView, aSuperView:UIView, width:CGFloat) 
        var constraint = NSLayoutConstraint(item: aChildView,
            attribute: NSLayoutAttribute.Width,
            relatedBy: NSLayoutRelation.Equal,
            toItem: nil,
            attribute: NSLayoutAttribute.NotAnAttribute,
            multiplier: 1.0,
            constant: width)
        aSuperView.addConstraint(constraint)
    


【讨论】:

以上是关于带有 ModalPresentationStyle 的弹出框不在 iOS 7 iPad 中居中的主要内容,如果未能解决你的问题,请参考以下文章

如何为自定义modalPresentationStyle禁用设置supportedInterfaceOrientations

containerView的自定义动画中的modalPresentationStyle .overCurrentContext返回黑屏

PresentViewController 与 ModalPresentationStyle “UIModalPresentationFormSheet” IOS 8

iOS 通用二进制 - 切换 ModalPresentationStyle

modalPresentationStyle 使用present跳转界面时,实现特殊的弹出效果。

iOS 6:旋转后忽略父模式的 modalPresentationStyle