UITableViewCell с autolayout левое поле отличается на iPhone и iPad


Я использую сгруппированы UITableView со статическими ячейками для экрана/сцены параметров. Все сделано в Xcode 6.1 / iOS 8.1.x / раскадровка с использованием автозапуска. Внутри групп таблиц есть смешанные типы ячеек и есть два типа, которые вызывают у меня проблемы:

  1. ячейки с пользовательским стилем и
  2. ячейки со стилем "правильная деталь"

в ячейке #1 я могу установить ограничение для левого поля между меткой и ведущим контейнером. На ячейка #2 я не могу установить какие-либо ограничения в Interface Builder, насколько я знаю. Я установил левое поле на метке в ячейке №1, чтобы оно совпадало с меткой в ячейке № 2. Все выглядит нормально на iPhone, но если я покажу ту же таблицу на iPad, где размер контейнера представления таблицы составляет половину размера экрана, ячейка #2 получает больше маржи (динамически?) в то время как ячейка № 1 поддерживает абсолютную маржу, которую я установил в ограничениях. Я также попытался изменить левое поле в ячейке №1 с атрибутом "относительно маржи", но безрезультатно.

iPhone:

iPad (с шириной tableview = 1/2 размера экрана)

Итак, вопрос: Как установить ограничения для метки в ячейке #1, чтобы она выравнивалась как ячейка #2.

вот также ссылка на пример проекта Xcode 6.1, демонстрирующий проблему. Работать на iPhone и iPad, чтобы увидеть разница:

https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.zip

этот вопрос может быть связано с макет статической ячейки таблицы для iPhone и iPad, но это может также отличаться для iOS 8, так как теперь все должно быть адаптивным. Вот почему я решил разместить этот вопрос.

5 53

5 ответов:

как это исправить

после борьбы с командой apple bug reporting со многими образцами проектов и скриншотов и рассечения что ответ, я обнаружил, что решение для того, чтобы ваши ячейки пользовательского стиля вели себя последовательно относительно их полей и были такими же, как uitableviewcells по умолчанию, вам нужно сделать следующее (в основном на основе Бекки!--8-->, я выделил, что отличается, и что заставило его работать на меня) :

  1. выберите просмотр содержимого в IB
  2. перейти к инспектору размера
  3. в разделе поля макета, проверьте сохранить поля супервизора (не нажимайте на знак плюс)

    Checking preserve superview margins

  4. (и вот ключ) сделайте то же самое для самой клетки (родитель представления содержимого, если вы Уилл)

    The cell and not the content view this time

  5. настройка ограничений следующим образом: метка.Ведущий = Супервизор.Ведущий запас (с константой 0)

    Setting the constraint for the custom cell's label

теперь все ваши ячейки будут иметь свою метку, соответствующую ячейкам по умолчанию! Это работает для меня в Xcode 7 и выше, и он включает в себя исправление, упомянутое в потоке, на который я ссылался. МБ и симулятор теперь должны отображаться правильно ценник.

Final result in the simulator

вы также можете сделать это программно, например, в классе контроллера вида:

cell.preservesSuperviewLayoutMargins = true
cell.contentView.preservesSuperviewLayoutMargins = true

или вы можете настроить его, вызвав UIAppearance один раз при запуске (я знаю только Swift, извините) :

UITableViewCell.appearance().preservesSuperviewLayoutMargins = true
UITableViewCell.appearance().contentView.preservesSuperviewLayoutMargins = true

как и почему он работает

как Итан любезно указал, что собственная документация Apple по UIView описывает preservesSuperviewLayoutMargins следующим образом :

когда значение этого свойства true, поля супервизора также учитываются при размещении контента. Это поле влияет на макеты, где расстояние между краем вида и его супервизором меньше, чем соответствующее поле. Например, у вас может быть представление содержимого, фрейм которого точно соответствует границам его супервизора. Когда любое из полей супервизора находится внутри области, представленной представлением содержимого и его собственными полями, UIKit настраивает макет представления содержимого с учетом полей супервизора. Размер корректировки-это наименьшая сумма, необходимая для обеспечения того, чтобы содержимое также находилось внутри полей супервизора.

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

почему это не поведение по умолчанию удивляет меня: я чувствую, что большинство разработчиков, которые не хотят настраивать все, ожидали бы этого "наследования" по умолчанию.

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

во-первых, немного фона: начиная с iOS 8, ячейки представления таблицы по умолчанию уважают ячейку layoutMargins для адаптации к различным чертам (ака экраны ака устройств). Например, поля макета на всех iPhones (кроме iPhone 6 Plus, когда они показаны на листе формы) являются {8, 16, 8, 16}. На iPad они {8, 20, 8, 20}. Итак, теперь мы знаем, что есть разница в 4 пикселя, которая, скорее всего, не соответствует вашей пользовательской ячейке представления таблицы уважать.

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

вот соответствующий фрагмент кода:

 - (void)layoutMarginsDidChange
{
    [super layoutMarginsDidChange];

    self.leftLayoutMarginConstraint.constant = self.layoutMargins.left;
    self.rightLayoutMarginConstraint.constant = self.layoutMargins.right;
}

адаптация к полям макета в коде позволяет вам всегда получать правильное заполнение для вашей метки заголовка.

вы также можете взглянуть на один из моих подклассов UITableViewCell, которые уже уважают layoutMargins: https://github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m

Ура

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

во-первых, это не обязательно устанавливать preservesSuperviewLayoutMargins к представлению ячейки или представлению содержимого как другоеответы подразумевают. В то время как значение по умолчанию:false об этом true не было никакого заметного эффекта, который я мог видеть.

ключ для этого на самом деле работа-это layoutMarginsGuide собственности на UIView. Используя это значение, мы можем просто легко закрепить leadingAnchor любого подвида к leadingAnchor руководства. Вот как это выглядит в коде (и вполне может быть то, что IB делает за кулисами, как в Джонас).

на UITableViewCell подкласс, вы бы сделали что-то вроде этого:

override func updateConstraints() {
    let margins = contentView.layoutMarginsGuide
    let leading = margins.leadingAnchor
    subview1.leadingAnchor.constraintEqualToAnchor(leading).active = true
    subview2.leadingAnchor.constraintEqualToAnchor(leading).active = true

    super.updateConstraints()
}

Swift 4.1 update

override func updateConstraints() {
    let margins = contentView.layoutMarginsGuide
    let leading = margins.leadingAnchor
    subview1.leadingAnchor.constraint(equalTo: leading).isActive = true
    subview2.leadingAnchor.constraint(equalTo: leading).isActive = true

    super.updateConstraints()
}

вот и все! Если вы разрабатываете для iOS версии до iOS 9 вам нужно будет заменить якоря макета и использовать layoutMargins вместо вставкой.


Примечание: я написал библиотеку, чтобы сделать якорь закрепления немного красивее, если вы предпочитаете более чистый синтаксис. Это называется SuperLayout и доступно на Cocoapods. В верхней части исходного файла, импорт SuperLayout:

import SuperLayout

а затем в вашем блоке макета, используйте ~~,≤≤ и ≥≥ для закрепления ограничений:

override func updateConstraints() {
    let margins = contentView.layoutMarginsGuide

    subview1.leadingAnchor ~~ margins.leadingAnchor
    subview2.leadingAnchor ~~ margins.leadingAnchor

    super.updateConstraints()
}

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

  1. в структуре документа выберите "вид содержимого" для ячейки с пользовательские стили.
  2. перейдите к инспектору размеров.
  3. в раскрывающемся списке " поля макета "нажмите маленький символ плюс рядом с" сохранить поля супервизора."
  4. выберите класс размера iPad ,который является " обычная ширина x обычная высота."
  5. Регистрация флажок рядом с "сохранить поля супервизора."
  6. разрешите любые предупреждения автоматической компоновки, обновив кадры.

Это сработало для меня в Xcode 7; я надеюсь, что он будет работать и в Xcode 6.

У меня была эта проблема при тестировании на iPad Air, OS 10.1.1. Заголовки таблицы были изрезаны гораздо дальше, чем должны были, и это было даже хуже в альбомной ориентации. Но они были в порядке на iPhone до OS 11.

удивительным решением была следующая строка кода, сразу после создания таблицы (Извините, я работаю только на C#, но легко разработать эквиваленты Obj-C и Swift):

myTableView.SeparatorInset = myTableView.SeparatorInset;

затем все было отступом, как и должно быть!