Popover с ModalPresentationStyle не центрируется в iOS 7 iPad

У меня проблема с 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, он будет работать нормально. Но только в этом режиме. Может, кто-то наткнулся и на эту и знает как исправить? Я не большой поклонник эффекта растворения. Спасибо.


person titicaca    schedule 22.09.2013    source источник


Ответы (6)


У меня есть метод, в котором старый пользовательский модальный стиль представления fromsheet работает с iOS <=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();
    });
}
person Alexander    schedule 02.10.2013
comment
Я приму этот ответ, поскольку он работает для меня, по крайней мере, на данный момент. Хотя в итоге я использовал MZFormSheetController - это действительно отличное решение в стиле ios 7, работает для меня в обеих версиях ios. Хотя я бы очень хотел в будущем выяснить, как справиться с этим с помощью родного набора ios, на данный момент это похоже на ошибку. - person titicaca; 07.10.2013
comment
эй, это не работает, просто появляется всплывающее окно и снова открывается полный вид на листе формы. любая идея об этом stackoverflow.com/questions/ 30615075 / - person Sanoj; 03.06.2015

У меня такая же проблема. Я решил это, используя другой подход, найденный здесь.

Это решение предлагает использовать метод (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); - четные числа, иначе текст внутри станет нечетким, если есть

person Tamara Bernad    schedule 26.09.2013
comment
Мне было интересно, может ли кто-нибудь объяснить, почему а) свойство view.superview.bounds должно быть вызвано, чтобы исправить эту проблему, и б) как передача (0,0) для происхождения прямоугольника заставляет его центрироваться? - person Evan R; 10.02.2014
comment
Я обнаружил, что viewWillAppear: - еще лучшее место для размещения self.view.superview.bounds=xxx, поскольку он вызывается раньше, чем viewWillLayoutSubviews - person wangii; 01.04.2014

Для меня проблема заключалась в вызове becomeFirstResponder в текстовом поле в viewDidAppear представленного контроллера представления. Кажется, это ошибка с этим сейчас. Решение заключалось в простом dispatch_async:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.userNameTextField becomeFirstResponder];
    });
}
person Bob Spryn    schedule 21.03.2014

У меня то же самое ... Пока не знаю, как это решить. В настоящее время я работаю над этой проблемой, поэтому я поделюсь всем, что получу!

Это мой код.

-(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;

}

person Manuel M.    schedule 22.09.2013
comment
Привет, Мануэль, ты нашел какое-нибудь решение? - person titicaca; 30.09.2013
comment
Привет! решение @Tamara Bernad работает очень хорошо. Попробуй. Я не могу проголосовать за хорошего, потому что у меня еще нет репутации :( - person Manuel M.; 30.09.2013
comment
К сожалению, у меня это не сработало. Он помещает всплывающее окно в центр, но оно не моего размера, это просто всплывающее окно стандартного размера с моими материалами по центру внутри него ... - person titicaca; 30.09.2013

Приведенное выше решение не сработало для меня. Я использовал следующее:

      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];
      }
person Peter B. Kramer    schedule 22.03.2014

Я сделал это несколько иначе, используя подклассовый контроллер навигации и AutoLayout в Swift, чтобы центрировать представление в супервизоре с заданной шириной и высотой. В моем конкретном случае требовалась поддержка 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)
    }

}
person mark.siedle    schedule 25.12.2014