Avatar ·

iOS 8 UITableView separator inset 0 не работает: как убрать отступы?

Привет всем! Я пишу приложение под iOS 8 на Swift, и столкнулся с проблемой, которая сводит меня с ума. Я хочу, чтобы разделительные линии (separator) в моей UITableView были без отступов, то есть шли от самого левого края до самого правого. Вроде бы всё просто: ставлю `tableView.separatorInset = UIEdgeInsetsZero` или `tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)`, но это не работает — отступы слева всё равно остаются. Я перепробовал всё: устанавливал inset в `viewDidLoad`, в `cellForRowAtIndexPath` для каждой ячейки, даже пытался переопределить `layoutMargins` у ячейки. Ничего не помогает. Вот мой код: ```swift override func viewDidLoad() { super.viewDidLoad() tableView.separatorInset = UIEdgeInsetsZero tableView.separatorStyle = .SingleLine } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) cell.separatorInset = UIEdgeInsetsZero // ... настройка ячейки return cell } ``` Я читал, что в iOS 7 это работало, но в iOS 8 появились какие-то `layoutMargins`. Может быть, дело в них? Подскажите, как правильно убрать отступы у separator в iOS 8? Я уже голову сломал, а в интернете куча противоречивых советов. Заранее спасибо! <<>>

Причина проблемы: layoutMargins в iOS 8

Вы абсолютно правы: в iOS 8 Apple ввела новое свойство layoutMargins у UIView, которое влияет на отображение separator у UITableView. Даже если вы устанавливаете separatorInset в ноль, система может игнорировать это из-за margins. Чтобы полностью убрать отступы, нужно обработать три уровня: саму таблицу, ячейку и её layoutMargins. Вот проверенное решение.

Решение: шаг за шагом

  1. Установите separatorInset для таблицы — это базовый шаг.
  2. Установите separatorInset для каждой ячейки — в методе cellForRowAtIndexPath.
  3. Переопределите layoutMargins у ячейки — задайте UIEdgeInsetsZero.
  4. Убедитесь, что ячейка не наследует 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.