iOS 8 UITableView separator inset 0 не работает: как убрать отступы?
Причина проблемы: layoutMargins в iOS 8
Вы абсолютно правы: в iOS 8 Apple ввела новое свойство layoutMargins у UIView, которое влияет на отображение separator у UITableView. Даже если вы устанавливаете separatorInset в ноль, система может игнорировать это из-за margins. Чтобы полностью убрать отступы, нужно обработать три уровня: саму таблицу, ячейку и её layoutMargins. Вот проверенное решение.
Решение: шаг за шагом
- Установите separatorInset для таблицы — это базовый шаг.
- Установите separatorInset для каждой ячейки — в методе
cellForRowAtIndexPath. - Переопределите layoutMargins у ячейки — задайте
UIEdgeInsetsZero. - Убедитесь, что ячейка не наследует margins от таблицы — установите
preservesSuperviewLayoutMargins = false.
Полный пример кода на Swift
override func viewDidLoad() {
super.viewDidLoad()
// 1. Убираем отступы у таблицы
tableView.separatorInset = UIEdgeInsetsZero
tableView.separatorStyle = .SingleLine
// Дополнительно: убираем отступы у самой таблицы (для iOS 8+)
if #available(iOS 8.0, *) {
tableView.layoutMargins = UIEdgeInsetsZero
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
// 2. Убираем отступы у ячейки
cell.separatorInset = UIEdgeInsetsZero
// 3. Убираем layoutMargins у ячейки (iOS 8+)
if #available(iOS 8.0, *) {
cell.layoutMargins = UIEdgeInsetsZero
cell.preservesSuperviewLayoutMargins = false // 4. Отключаем наследование margins
}
// Настройка содержимого ячейки
cell.textLabel?.text = "Строка \(indexPath.row)"
return cell
}
Почему это работает?
separatorInset— напрямую управляет отступами разделителя, но в iOS 8 он переопределяется margins.layoutMargins— это свойство появилось в iOS 8 и влияет на то, как UIView отображает свои дочерние элементы, включая separator. Установка его в ноль заставляет систему игнорировать стандартные отступы.preservesSuperviewLayoutMargins— если оставитьtrue(значение по умолчанию), ячейка будет наследовать margins от таблицы. Установкаfalseгарантирует, что margins ячейки будут использоваться как есть.
Дополнительные советы
- Если у вас используются кастомные ячейки (созданные через XIB), проверьте, что в XIB у ячейки также установлены
Layout Marginsв ноль (в инспекторе Size Inspector). - Для iOS 9 и выше можно использовать свойство
cellLayoutMarginsFollowReadableWidthу таблицы, установив его вfalse, чтобы отступы не адаптировались под ширину экрана. - Если вам нужно убрать separator только для некоторых ячеек, вы можете установить
separatorInsetиндивидуально, а для остальных оставить стандартные значения.
После применения этого кода разделительные линии будут идти от края до края, как вы и хотели. Удачи!
<<Альтернативный подход: использование UITableViewDelegate
Если вы не хотите модифицировать каждую ячейку в cellForRowAtIndexPath, можно использовать делегат таблицы. Это особенно удобно, если у вас много разных типов ячеек или вы хотите централизованно управлять отступами.
override func viewDidLoad() {
super.viewDidLoad()
tableView.separatorInset = UIEdgeInsetsZero
tableView.layoutMargins = UIEdgeInsetsZero
}
// Реализуем метод делегата
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.separatorInset = UIEdgeInsetsZero
cell.layoutMargins = UIEdgeInsetsZero
cell.preservesSuperviewLayoutMargins = false
}
Этот метод вызывается перед отображением каждой ячейки, поэтому вы гарантированно применяете настройки после того, как ячейка полностью сконфигурирована. Преимущество: код чище, особенно если вы используете Storyboard или XIB и не хотите переписывать cellForRowAtIndexPath.
Когда это может не сработать?
- Если у вас кастомная ячейка с переопределённым
layoutSubviews, где margins снова меняются. - Если вы используете сторонние библиотеки для таблиц (например,
RxDataSources), которые могут переопределять эти свойства.
В таких случаях комбинируйте оба подхода: установите базовые значения в viewDidLoad и переопределите их в willDisplayCell.