Настройка TranslatesAutoresizingMaskIntoConstraints на No на UIPageViewController

Я строю сложный проект, где, среди прочего, мне нужно установить UIPageViewController как дочернее представление основного вида. Я использую autolayout и используя ограничения для упорядочения различных элементов основного вида.

Проблема в том, что когда я пытаюсь запустить приложение, он выходит из строя из-за противоречивых NSAutoresizingMaskLayoutConstraints.

2013-10-28 16:22:18.419 Red Event App[1658:60b] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
"<NSLayoutConstraint:0x145c1990 V:|-(20)-[UINavigationBar:0x145bf6b0]   (Names: '|':UIView:0x145bf620 )>",
"<NSLayoutConstraint:0x145bf510 V:[UINavigationBar:0x145bf6b0]-(0)-[UIView:0x145bef70]>",
"<NSLayoutConstraint:0x145d0550 UIView:0x145a8c10.top == UIView:0x145bf620.top>",
"<NSAutoresizingMaskLayoutConstraint:0x145b3a40 h=-&- v=-&- UIView:0x145a8c10.midY == UIView:0x145bef70.midY + 56.5>",
"<NSAutoresizingMaskLayoutConstraint:0x145b3a70 h=-&- v=-&- UIView:0x145a8c10.height == UIView:0x145bef70.height + 113>"
)

Обычным средством для этого является установка TranslatesAutoresizingMaskIntoConstraints на no.

Однако, когда я это делаю, дочерние представления UIPageViewController начинают игнорировать границы PageViewController и заканчивают (насколько я вижу) с началом (0,0).

Я попытался исправить положение, установив рамки вручную как при настройке источника данных (_itemViewControllers):

- (void)setupLeafs{
    _itemViewControllers = [[NSMutableArray alloc]init];
    for(NSString *pagename in _datasource){
        RWNode *page = [_xml getPage:pagename];
        UIViewController *viewController = [RWNavigationController getViewControllerFromDictionary:[page getDictionaryFromNode]];
        viewController.view.frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y,self.view.frame.size.width, self.view.frame.size.height);

       [_itemViewControllers addObject:viewController];
   }
}

и при получении страницы

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    UIViewController *nextViewController = [self getPreviousLeaf:viewController];
    nextViewController.view.frame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y,self.view.frame.size.width, self.view.frame.size.height);
    return nextViewController;
}

но не имеет никакого эффекта.

Мне нужны ограничения для того, что я делаю, поэтому придерживаться Масок не вариант. Я думаю, что я ищу способ установить ограничения на дочерние элементы UIPageViewController после того, как они были добавлены (любыми вызовами процесса viewControllerBeforeViewController). Но мне очень хотелось бы услышать, как можно решить эту проблему.

Edit: Я нашел взломать решение проблемы. Я не совсем уверен, что то, что я перечисляю здесь, - это все решение, но это то, что я замечаю прямо сейчас, после того, как более месяца возится с кодом.

Во-первых, в контроллере представления, который настраивает контроллер просмотра страницы, у меня есть следующие две строки после того, как я инициализировал pageviewcontroller

UIView *pageView = self.pageViewController.view; 
pageView.frame = self.view.frame;

Не то, что я установил [self.view setTranslatesAutoresizingMaskIntoConstraints:NO]; в этом контроллере представления.

Во-вторых, на дочерних контроллерах я проверяю, используется ли представление внутри или вне контроля просмотра страницы. Только если представление не используется в диспетчере просмотра страницы, [self.view setTranslatesAutoresizingMaskIntoConstraints:NO]; установлен на дочернем представлении.

Теперь это работает (для меня) на данный момент. Но мне бы очень хотелось, чтобы решение было менее взломанным.

Ответ 1

При использовании AutoLayout вы никогда не должны напрямую устанавливать рамку представления. Для этого используются ограничения. Обычно, если вы хотите установить свои собственные ограничения в представлении, вы переопределяете метод updateConstraints своих UIViews. Убедитесь, что просмотры содержимого для контроллера страниц позволяют изменять их края, поскольку они будут иметь размер, соответствующий размеру окна просмотра страницы. Ваши ограничения и настройки просмотра должны будут учитывать это, или вы получите недопустимые ошибки ограничения.

Ответ 2

Пока я не знаю точно, чего вы пытаетесь достичь визуально, вот два совета, которые могут вам помочь:

Во-первых, не забудьте удалить все существующие ограничения из UIView перед добавлением новых в код. Не смешивайте ограничения с Interface Builder с ограничениями в коде, это сбивает вас с ума. Пример:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // remove all constraints
    [self.view removeConstraints:self.view.constraints];

    // add new constraints
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[webView]|"
                                                                      options:0
                                                                      metrics:nil
                                                                        views:@{@"webView": self.webView}]];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[webView]|"
                                                                      options:0
                                                                      metrics:nil
                                                                        views:@{@"webView": self.webView}]];
}

Во-вторых, вы можете иметь выходы NSLayoutConstraint, как и любые другие выходы из XIB или раскадровки. Таким образом, вы можете настроить определенные свойства ограничения во время выполнения:

// in your header:
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *myConstraint;

// somewhere in your code where you need to adjust the constraint:
self.myConstraint.constant = 100;

Надеюсь, это немного поможет:)

Ответ 3

Я не могу дать вам ответ, но, возможно, я могу дать вам несколько советов по отладке. Скопируйте информацию журнала в текстовый редактор и замените информацию о адресе памяти для представлений с содержательными именами. (используйте отладчик, чтобы найти, к каким свойствам относятся карты памяти, если вы не можете понять это). Тогда вам будет немного легче понять информацию журнала и проследить конфликт. Вот пример (хотя я просто догадываюсь о вашей иерархии представлений)

"<NSLayoutConstraint:0x145c1990 V:|-(20)-[UINavigationBar:NAVBAR]   (Names: '|':UIView:ROOTVIEW )>",
"<NSLayoutConstraint:0x145bf510 V:[UINavigationBar:NAVBAR]-(0)-[UIView:PAGECONTAINER]>",
"<NSLayoutConstraint:0x145d0550 UIView:PAGEVIEW.top == UIView:ROOTVIEW.top>",
"<NSAutoresizingMaskLayoutConstraint:0x145b3a40 h=-&- v=-&- UIView:PAGEVIEW.midY == UIView:PAGECONTAINER.midY + 56.5>",
"<NSAutoresizingMaskLayoutConstraint:0x145b3a70 h=-&- v=-&- UIView:PAGEVIEW.height == UIView:PAGECONTAINER.height + 113>"

В предположении, что последние два авторезистентных макета для меня выглядят странно, они не выглядят четко определенными.

Ответ 4

Я столкнулся с подобной ситуацией. Если я установил какие-либо ограничения в представлении UIPageViewController, это вызовет конфликты с ограничениями маскировки автосохранения.

Что для меня работает - это установить translatesAutoresizingMaskIntoConstraints в NO для представления UIPageController, а затем добавить ограничения в родительское представление для просмотра верхнего уровня страницы, слева, ширины и высоты.

  self.pageController.view.translatesAutoresizingMaskIntoConstraints = NO;

  NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:self.pageController.view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
  NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:self.pageController.view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0];
  NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:self.pageController.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1.0 constant:-60.0];
  NSLayoutConstraint *constraint4 = [NSLayoutConstraint constraintWithItem:self.pageController.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0];

  [self.view addConstraints:@[constraint1, constraint2, constraint3, constraint4]];