Подтвердить что ты не робот

UITableViewCell с автозапуском левого края отличается от iPhone и iPad

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

  • Ячейки с пользовательским стилем и
  • Ячейки со стилем "Правая деталь"

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

iPhone:

Table on iPhone

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

Table on iPad

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

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

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

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

4b9b3361

Ответ 1

Как исправить его

После борьбы с командой отчетов об ошибках Apple со множеством примеров проектов и скриншотов и анализом который отвечает, я обнаружил, что решение иметь ваши ячейки пользовательского стиля вести себя последовательно относительно их маржи и быть таким же, как UITableViewCells по умолчанию, вы должны сделать следующее (в основном на основе ответа Бекки, я подсказал, что другое и что сделало его работа для меня):

  • Выберите вид вашей ячейки в IB
  • Перейдите к Инспектору размеров
  • В разделе "Поля макета" установите флажок "Сохранять поля надзора" (не нажимайте знак "плюс" )

    Проверка полей сохранения супервизора

  • (И вот этот ключ). Сделайте то же самое для самой ячейки (родительский контент, если вы это сделаете)

    Ячейка, а не просмотр содержимого на этот раз

  • Задайте свои ограничения следующим образом: Label.Leading = Superview.Leading Margin (с константой 0)

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

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

Конечный результат в симуляторе

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

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

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

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

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

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

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

Поэтому, если вы хотите, чтобы содержимое вашей ячейки совпадало с полями TableView (это отличное дедушка, если хотите), вам нужно иметь в своем содержании два восходящих канала, Content View и сам Table Cell, сохраняют поля собственного наблюдения.

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

Ответ 2

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

Во-первых, небольшой фон: поскольку iOS 8, ячейки таблицы по умолчанию рассматривают ячейку layoutMargins для адаптации к различным признакам (например, к экранам aka devices). Например, макеты макета на всех iPhone (кроме 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, которые уже уважают макеты макетов: https://github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m

Приветствия

Ответ 3

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

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

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

В подклассе 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

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()
}

ios 11+: пусть margins = contentView.directionalLayoutMargins ... на случай, если вам нужно адаптироваться к LTR и RTL из коробки. Я предполагаю, что большинству людей это нужно.

Ответ 4

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

  • В схеме документа выберите "Просмотр содержимого" для ячейки с пользовательский стиль.
  • Перейдите к Инспектору размеров.
  • В раскрывающемся списке "Макет полей" нажмите значок "плюс плюс" рядом с "Сохранить поля надзора".
  • Выберите класс размера iPad, который является "Regular Width x Regular Height".
  • Установите флажок рядом с надписью "Сохранять поля надзора".
  • Разрешить любые предупреждения Auto Layout путем обновления фреймов.

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

Ответ 5

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

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

myTableView.SeparatorInset = myTableView.SeparatorInset;

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