Автоматическая компоновка дочернего контейнера, в который встроен UIViewController.

Моя основная сцена показывает дочерний элемент UIViewController, помещая дочерний контейнер в его представление и встраивая дочерний UIViewController в этот дочерний контейнер. Я делаю это, перетаскивая с нажатой клавишей Ctrl из дочернего контейнера в дочерний элемент UIViewController в storyboard и выбирая переход «встроить».

Это позволяет мне инкапсулировать и повторно использовать дочерний элемент UIViewController в другом месте. Я думаю, что это достаточно стандартно. Но я не могу правильно настроить автоматическую компоновку.

Я сделал простой тестовый пример, чтобы продемонстрировать это: https://github.com/murraycu/ios-example-autolayout-of-child-container-views

Он имеет два UIViewControllers, которые встроены в контроллер вкладок, поэтому вы можете переключаться между ними.

На вкладке «Простой» отображается SimpleViewController, на котором показано изображение и метка, показанные здесь в раскадровке:

SimpleViewController

Ни для UIImage, ни для UILabel не указано ограничение высоты, хотя у них есть ограничение Equal Width (равное родительскому представлению), чтобы ширина оставалась простой.

Этот UILabel явно не очень высок, но UIImage и UILabel имеют немного разные приоритеты обтягивания содержимого, что делает их высоты не двусмысленными в соответствии с Auto Layout. Таким образом, благодаря автоматической компоновке, когда я устанавливаю его текст во время выполнения на какой-то текст, который потребует больше места, он занимает больше места, отнимая место у UIImage над ним. Это хорошо - это поведение, которое я хочу, как показано в эмуляторе:

SimpleViewController в эмуляторе

Теперь к проблеме: на вкладке «С дочерним контейнером» отображается WithChildContainerViewController, который показывает то же изображение, но показывает мой ChildViewController (встроенный в дочерний контейнер) вместо UILabel. И этот встроенный ChildViewController показывает UILabel. Вот он в раскадровке:

WithChildContainerViewController

Однако система автоматической компоновки теперь, похоже, не знает, сколько места нужно дочернему контейнеру для отображения всего текста в метке в моем ChildViewController. Как и на вкладке «Простой», ни для UIImage, ни для дочернего контейнера не указано ограничение по высоте. Теперь XCode жалуется, что «Высота неоднозначна для «представления контейнера». И в симуляторе это выглядит так:

СChildContainerViewController в эмуляторе

Это улучшится, если я добавлю ограничение в дочерний контейнер, ограничивая его нижнюю часть нижней частью родительского представления, как это было предложено @iphonic: https://github.com/murraycu/ios-example-autolayout-of-child-container-views/commit/1d295fe0a6c4502938f89925d но высота все еще неправильная:

введите здесь описание изображения

Как я могу сообщить системе автоматической компоновки, что делать? Я думал о реализации встроенного ContentSize UIView, но UIViewController не является UIView.


person murrayc    schedule 23.06.2015    source источник
comment
Вам нужно добавить ограничения на ChildViewController's View в отношении контейнера, в котором вы отображаете дочерний элемент.   -  person iphonic    schedule 23.06.2015
comment
Спасибо. Звучит хорошо, но я не могу перетащить Ctrl-Drag из основного представления дочернего контроллера представления в containerView (дочерний контейнер) в другой (родительской) сцене. Не могли бы вы быть более конкретным, пожалуйста?   -  person murrayc    schedule 23.06.2015
comment
@murrayc ты когда-нибудь решал эту проблему? я испытываю то же самое   -  person Lneuner    schedule 22.12.2016
comment
Я думаю, что исправил это в коде, как в ответе iPhonic, и в комментариях ниже. Я не нашел способа сделать это без предупреждений о макете. Я сделал это в своем проекте ios-galaxyzoo: github.com/murraycu/ios-galaxyzoo и я думаю, что сделал это в примере проекта: github. com/murraycu/ . Прошло некоторое время с тех пор, как я думал об этом.   -  person murrayc    schedule 22.12.2016


Ответы (2)


Предложение состоит в том, чтобы сделать это программно, а не через IB. Смотри ниже

 _childController=[self.storyboard instantiateViewControllerWithIdentifier:@"ChildController"];

    [self addChildViewController:_childController];
    [_container addSubview:_childController.view];
    [_childController didMoveToParentViewController:self];

    _childController.view.frame=_container.bounds;


    //add constraints        
    UIView *subView=_childController.view;
    UIView *parent=_container;


    subView.translatesAutoresizingMaskIntoConstraints=NO;

    NSLayoutConstraint *width =[NSLayoutConstraint
                                    constraintWithItem:subView
                                    attribute:NSLayoutAttributeWidth
                                    relatedBy:0
                                    toItem:parent
                                    attribute:NSLayoutAttributeWidth
                                    multiplier:1.0
                                    constant:0];
    NSLayoutConstraint *height =[NSLayoutConstraint
                                     constraintWithItem:subView
                                     attribute:NSLayoutAttributeHeight
                                     relatedBy:0
                                     toItem:parent
                                     attribute:NSLayoutAttributeHeight
                                     multiplier:1.0
                                     constant:0];
   NSLayoutConstraint *top = [NSLayoutConstraint
                                   constraintWithItem:subView
                                   attribute:NSLayoutAttributeTop
                                   relatedBy:NSLayoutRelationEqual
                                   toItem:parent
                                   attribute:NSLayoutAttributeTop
                                   multiplier:1.0f
                                   constant:0.f];

NSLayoutConstraint *leading = [NSLayoutConstraint
                                           constraintWithItem:subView
                                           attribute:NSLayoutAttributeLeading
                                           relatedBy:NSLayoutRelationEqual
                                           toItem:parent
                                           attribute:NSLayoutAttributeLeading
                                           multiplier:1.0f
                                           constant:0.f];
    [parent addConstraint:width];
    [parent addConstraint:height];
    [parent addConstraint:top];
    [parent addConstraint:leading];

Надеюсь, поможет.

Ваше здоровье.

person iphonic    schedule 23.06.2015
comment
Спасибо. Я попробовал это в ветке здесь: github.com/murraycu/ Это улучшает ситуацию — теперь я вижу хотя бы текст, но метка/дочерний вид теперь занимают слишком много места по вертикали. Я поместил скриншот в конце вопроса, потому что я не могу разместить его здесь. - person murrayc; 23.06.2015
comment
@murrayc Я видел ваш код, все в порядке, но в контроллере WithChild вам нужно установить нижнее ограничение для контейнера с суперпредставлением, которое отсутствует, и у вас отображается ошибка макета. добавь, работает нормально.. - person iphonic; 23.06.2015
comment
@murrayc См. мой форк здесь github.com/iphonic/ - person iphonic; 23.06.2015
comment
Превосходно. Да, спасибо, добавление этого нижнего ограничения исправило следующее: >github.com/murraycu/ Я также добавил это в обычную ветку (без ограничений в коде) и обновлю скриншоты, хотя нам все еще нужен код, чтобы он действительно работал. Вы знаете, можно ли это сделать только в раскадровке без кода? - person murrayc; 23.06.2015
comment
Также было бы неплохо избежать двух предупреждений раскадровки Misplaced View, которые остаются, даже в вашем форке, о том, что фреймы containerView и testImage отличаются во время выполнения. - person murrayc; 23.06.2015
comment
@murrayc Я обновил ограничения и обновил. Он должен исправить неточности. - person iphonic; 23.06.2015
comment
Спасибо, но это соотношение сторон использует жестко запрограммированное соотношение, основанное на позиции с этим текстом, поэтому imageView больше не меняет свой размер при изменении текста. В любом случае, я с радостью принимаю ответ на данный момент, хотя я бы предпочел сделать это без предупреждений о макете и, в идеале, установив ограничения в раскадровке вместо кода. Большое спасибо. - person murrayc; 23.06.2015

Код @iphonic, но с использованием языка визуального формата

_childController = [self.storyboard instantiateViewControllerWithIdentifier: @"ChildController"];

[self addChildViewController: _childController];
[_container addSubview: _childController.view];
[_childController didMoveToParentViewController: self];

//add constraints
NSDictionary *views = @{@"subView": _childController.view, 
                        @"parent": _container};

[parent addConstraints:[NSLayoutConstraint
                        constraintsWithVisualFormat: @"V:|[subView(==parent)]"
                        options: 0
                        metrics: nil
                        views: views]];

[parent addConstraints: [NSLayoutConstraint
                         constraintsWithVisualFormat:@"H:|[subView(==parent)]"
                         options: 0
                         metrics: nil
                         views: views]];
person benoit    schedule 09.11.2015
comment
Разве вам не нужно перечислять ограниченияWithVisualFormat о subView и parent через параметр views? - person murrayc; 23.11.2015