Динамический тип и саморазмерные ячейки со статической таблицей

У меня есть типичное приложение для мастер-деталей, которое позволяет пользователю просматривать список объектов с прокруткой, а затем сверлить до деталей для любого конкретного объекта с помощью push-сегмента. Список основных прокруток - это UITableView, созданный с ячейками прототипа, а сценка деталей - статический UITableView с фиксированным числом разделов и ячеек.

Я хотел бы использовать Dynamic Type и Self-Sizing Cells в своем приложении, чтобы пользователь мог изменить размер базового шрифта. До сих пор мне удалось создать ячейки для самостоятельной калибровки с прокручивающимся списком прототипов: используя Auto Layout, установив количество строк на каждой метке равным 0 и установив tableView.rowHeight = UITableViewAutomaticDimension, высота каждой ячейки прототипа растет или сжимается для размещения размера текста внутри.

Но я не могу добиться такого же эффекта в моем статическом представлении таблицы. Я использую пользовательские ячейки или встроенные типы ячеек, шрифт растет/сжимается, но высота ячейки не делает.

Итак, мой вопрос на самом деле состоит в двух вопросах: 1) возможно ли реализовать саморазмерные ячейки в статических табличных представлениях, например, я сделал это со своим представлением таблицы прототипов? и 2) если ответ на первый вопрос отсутствует, как написать код, который будет измерять высоту метки в ячейке представления статического стола и соответствующим образом отрегулировать высоту ячейки?

Спасибо!

Ответ 1

Я благодарен за ответы на вопрос, который я опубликовал вчера. К сожалению (и, вероятно, из-за моей собственной неопытности как программиста iOS) мне не удалось заставить работать метод systemLayoutSizeFittingSize (UILayoutFittingCompressedSize). Однако после некоторых проб и ошибок я нашел другой метод, который, кажется, работает:

import UIKit

class MasterTVC: UITableViewController {
    @IBOutlet weak var staticCustomCellLabel: UILabel!

    //viewDidLoad
    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.estimatedRowHeight = 44.0

        staticCustomCellLabel.text = "This is the text for the static custom cell label; This is the text for the static custom cell label; This is the text for the static custom cell label"

        //Register handleDynamicTypeChange in observer: self
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleDynamicTypeChange:", name: UIContentSizeCategoryDidChangeNotification, object: nil)
    }

    //deinit
    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    //handleDynamicTypeChange
    //called when user changes text size in Settings > General > Accessibility > Larger Text
    //or Settings > Display & Brightness > Text Size
    func handleDynamicTypeChange(notification: NSNotification) {
        staticCustomCellLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)

        self.tableView.reloadData()
    }

    //tableView:heightForRowAtIndexPath
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
}

На стороне раскадровки установка начинается с одного контроллера табличного представления со следующими свойствами:

  • Класс: MasterTVC (мой пользовательский класс);
  • обозначает контроллер начального представления;
  • Содержимое: статические ячейки;
  • Стиль: сгруппировано
  • Разделы: 1.

Раздел-1:

  • Строки: 1.

Элемент просмотра таблицы:

  • Стиль: Пользовательский (при использовании Basic здесь происходит исчезновение метки при изменении размера текста в настройках);
  • Содержит UILabel.

UILabel далее конфигурируется как:

  • Шрифт: Тело (стиль динамического типа);
  • Линии: 0;
  • Прикрепленный на всех четырех сторонах к верхнему, нижнему, левому и правому краям представления содержимого (я использовал соответствующие ограничения 8, 8, 15, 15);
  • с @IBOutlet в коде пользовательского класса.

Это сработало для меня для iOS 9 в Xcode 7 и Swift 2 с автоматической компоновкой. Интересно то, что если вы отмените код NSNotificationCenter, который будет использоваться для немедленного реагирования на изменения размера текста, код ячеек для самостоятельной калибровки в основном состоит из двух строк: установка оценочногоRowHeight в viewDidLoad и возврат UITableViewAutomaticDimension из tableView: heightForRowAtIndexPath.

Основываясь на этих результатах, я считаю, что ответы на мой первоначальный вопрос: 1) да; и 2) см. 1.

Ответ 2

Представления статической таблицы возвращают высоту строки, заданную в Interface Builder. Настройка tableView.rowHeight кажется полностью игнорируемой. Это, по-видимому, ошибка в UIKit.

Чтобы исправить это, просто переопределите -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath и верните UITableViewAutomaticDimension.

Ответ 3

Сначала добавьте две функции в свой класс

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Во-вторых, чтобы сделать работу UITableViewAutomaticDimension, убедитесь, что вы добавили все левые, правые, нижние и верхние ограничения относительно представления контейнера ячеек. Также не забудьте установить номер метки строки в ноль.

Ответ 4

Поскольку это статическая таблица, вы не можете деактивировать ячейки, поэтому вам придется создавать IBOutlets для них, я бы сохранил их в таком массиве:

@IBOutlet var cells: [UITableViewCell]!  

Затем вам придется реализовать heightForRowAtIndexPath и рассчитать размер:

var rowSizes: [Int: CGFloat] = [:]

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return calculateHeightForCell(indexPath)
}

func calculateHeightForCell(indexPath: NSIndexPath) -> CGFloat {

    // check if we already calculated the height
    if let height = rowSizes[indexPath.row] {
        return height
    }

    // else, calculate it
    let cell = cells[indexPath.row]

    let size = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

    rowSizes[indexPath.row] = size.height

    return size.height
}

rowSizes действует как кеш, он будет удерживать высоту строки, поэтому они будут вычисляться только один раз. При изменении размера шрифта просто запустите rowSizes и обновите таблицу, чтобы они снова были рассчитаны.