UIView не подчиняется ограничениям автомакета в UIScrollView

Я добавляю UIView к UIScrollView и ограничиваю его так, чтобы он заполнил горизонтальное пространство, за исключением некоторых полей. Мое визуальное ограничение выглядит так:

@"|-16-[theLineView]-16-|"

Я сделал вид высотой в один пиксель, чтобы он отображался в виде линии, и поместил его между двумя текстовыми метками:

@"V:[someOtherStuff]-[aTextLabel]-[theLineView]-[anotherLabel]"

Однако я обнаружил, что ширина линии увеличивается только до ширины самой длинной метки над/под ней.

С чего бы это?

PS Я прочитал это http://developer.apple.com/library/ios/#technotes/tn2154/_index.html

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

Код

Вот полный код контроллера представления из тестового проекта, который демонстрирует эту проблему на симуляторе iPad.

- (void)viewDidLoad

{ [супер viewDidLoad];

self.scrollView = [[UIScrollView alloc] init];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
self.scrollView.backgroundColor = [UIColor greenColor];
[self.view addSubview:self.scrollView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[scrollView]|"
                                                                 options:0
                                                                 metrics:0
                                                                   views:@{@"scrollView":self.scrollView}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
                                                                  options:0
                                                                  metrics:0
                                                                    views:@{@"scrollView":self.scrollView}]];

self.line1 = [[UIView alloc] init];
self.line2 = [[UIView alloc] init];
self.label1 = [[UILabel alloc] init];
self.label2 = [[UILabel alloc] init];
self.label3 = [[UILabel alloc] init];

for (UILabel *label in @[self.label1, self.label2, self.label3])
{
    label.text = @"I am a label and I am long enough that I can be multiline on an iphone but single on ipad";
}

for (UIView *view in @[self.line1, self.line2, self.label1, self.label2, self.label3])
{
    view.translatesAutoresizingMaskIntoConstraints = NO;
    view.backgroundColor = [UIColor redColor];
    [self.scrollView addSubview:view];
}

//horizontal layout - all views/labels should fill the horizontal space expect for margin
for (UIView *view in  @[self.line1, self.line2, self.label1, self.label2, self.label3])
{
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-16-[view]-16-|"
                                                                   options:0
                                                                   metrics:0
                                                                     views:@{@"view":view}];
    [self.scrollView addConstraints:constraints];
}

//vertical layout - stack em up
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[lab1]-[line1(==1)]-[lab2]-[line2(==1)]-[lab3]-|"
                                                                  options:0
                                                                  metrics:0
                                                                    views:@{@"lab1":self.label1, @"line1":self.line1, @"lab2":self.label2, @"line2":self.line2, @"lab3":self.label3}]];

}


person Ben Packard    schedule 21.07.2013    source источник
comment
Есть ли у вашего 1px UIView какие-либо другие ограничения?   -  person Yazid    schedule 21.07.2013
comment
Является ли [view] тем же видом, что и [theLineView]? Есть ли у вас какие-либо настройки параметров выравнивания в параметре параметров?   -  person rdelmar    schedule 21.07.2013
comment
Никаких других ограничений или чего-либо в параметре options. Я посмотрю, смогу ли я воспроизвести в тестовом проекте. Да, эти взгляды одинаковы, исправил фрагмент.   -  person Ben Packard    schedule 21.07.2013
comment
См. здесь: stackoverflow.com/questions/16843633/   -  person catamphetamine    schedule 14.01.2014


Ответы (4)


UIScrollView автоматически сжимается, чтобы соответствовать представлениям внутри него. Вам нужно установить ширину абсолютно где-то.

Рекомендуемая тактика:

  1. Полностью зафиксируйте представление прокрутки внутри его родительского представления, используя ограничения (начальные, конечные, верхние, нижние).
  2. Создайте UIView внутри UIScrollView и поместите в него все, что вам нужно.
  3. Установите ограничения так, чтобы UIView действовал как представление содержимого (это означает, что оно достаточно велико, чтобы включать все элементы). Чаще используйте внутренний размер содержимого, устойчивость к сжатию и цепочку элементов с ограничениями. Результирующий макет должен быть четко определенным и уникальным (это означает, что если вы удалите все внешние ограничения, макет все равно будет работать).
  4. Соедините границы UIView с их суперпредставлением (которое является фактическим представлением содержимого UIScrollView, а НЕ UIScrollView!).

Если вы делаете это в конструкторе интерфейсов (это возможно), вам нужно перепроверять свои ограничения каждый раз, когда вы касаетесь чего-либо в этой сцене. И под прикосновением я подразумеваю «выбрать», а не только «изменить».

person patric.schenke    schedule 21.07.2013
comment
У меня не сработало, как настроить UIView на заполнение всей ширины прокрутки? - person AndiDog; 24.09.2013
comment
Как я уже сказал: contentView ВСЕГДА заполняет весь scrollView, потому что scrollView сжимается. Вы ДОЛЖНЫ установить ширину внутри. В вашем примере изменение формата с |-16-[view]-16-| к |-16-[просмотр(288)]-16-| должен дать вам хороший результат. - person patric.schenke; 24.09.2013
comment
Это работает. Номер 4, на мой взгляд, является лучшим подходом, поскольку он прост и позволяет избежать любых магических чисел (что означает, что он поддерживает вращение и т. д.). - person Ben Packard; 24.09.2013

Нашел рабочее решение, которое должно работать и для вашего варианта использования. См. здесь.

person AndiDog    schedule 24.09.2013

Расширение номера 4 ответа Патрика Шенке; поскольку размер содержимого scrollView является изменчивым, прикрепление внутреннего представления к его краям просто не работает для определения ширины представления. Ваш левый штифт будет работать, но оба — нет. Вычисление ширины вашего представления на основе контейнера следующего уровня — это путь. Пока ваш self.scrollView закреплен заподлицо со своим контейнером (который я называю containerView), эта строка кода будет выполнять то, что вы хотите. Добавьте эту строку в цикл for для горизонтальных ограничений:

// Pin view's width to match the scrollView container's width
// -32 constant offset for margins
[containerView addConstraint:
  [NSLayoutConstraint constraintWithItem:view 
                               attribute:NSLayoutAttributeWidth
                               relatedBy:NSLayoutRelationEqual
                                  toItem:containerView
                               attribute:NSLayoutAttributeWidth
                              multiplier:1.0f
                                constant:-32]];
person Joel H.    schedule 25.02.2014

Я нашел простой способ сделать это на основе ограничений (я не проверял степень хрупкости этого решения):

...@"H:|-16-[view]-16-|"... // (your original constraint)

[self.scrollView addConstraint:
  [NSLayoutConstraint constraintWithItem:view 
                               attribute:NSLayoutAttributeCenterX
                               relatedBy:NSLayoutRelationEqual
                                  toItem:self.scrollView
                               attribute:NSLayoutAttributeCenterX
                              multiplier:1.0f
                                constant:0.0f]];

Это растягивает view полностью на другую сторону вида. Вероятно, это не идеально для контента, который прокручивается горизонтально, но должен работать вертикально.

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

person DanBlakemore    schedule 29.10.2014