Настройка 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]];