Пример настраиваемого подкласса UIView
Обычно я создаю приложения для iOS без раскадровок и перьев. Я поделюсь некоторыми методами, которые я научился отвечать на ваши вопросы.
Скрытие нежелательных initметодов
Мое первое предложение - объявить базу UIViewдля скрытия нежелательных инициализаторов. Я подробно обсуждал этот подход в своем ответе на вопрос «Как скрыть инициализаторы, специфичные для раскадровки и перьев, в подклассах пользовательского интерфейса» . Примечание. Этот подход предполагает, что вы не будете использовать BaseViewего потомки в раскадровках или перьях, поскольку это намеренно приведет к сбою приложения.
class BaseView: UIView {
init() {
super.init(frame: CGRect.zero)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
Ваш собственный подкласс UIView должен наследовать от BaseView. Он должен вызывать super.init () в своем инициализаторе. Это не нужно реализовывать init(coder:). Это показано в примере ниже.
Добавление UITextField
Я создаю сохраненные свойства для подпредставлений, на которые есть ссылки вне initметода. Я обычно делал это для UITextField. Я предпочитаю , чтобы создать экземпляр подвиды в декларации имущества подвида , как это: let textField = UITextField().
UITextField не будет отображаться, если вы не добавите его в список подпредставлений пользовательского представления, вызвав addSubview(_:). Это показано в примере ниже.
Программный макет без автоматического макета
UITextField не будет отображаться, пока вы не установите его размер и положение. Я часто делаю макет в коде (не используя Auto Layout) в методе layoutSubviews . layoutSubviews()вызывается изначально и всякий раз, когда происходит событие изменения размера. Это позволяет настраивать макет в зависимости от размера CustomView. Например, если CustomView отображается во всю ширину на iPhone и iPad разных размеров и регулируется для поворота, ему необходимо приспособиться к множеству исходных размеров и динамически изменять размер.
Вы можете обратиться к frame.heightи frame.widthвнутри, layoutSubviews()чтобы получить размеры CustomView для справки. Это показано в примере ниже.
Пример подкласса UIView
Пользовательский подкласс UIView, содержащий UITextField, который не нужно реализовывать init?(coder:).
class CustomView: BaseView {
let textField = UITextField()
override init() {
super.init()
textField.placeholder = "placeholder text"
textField.font = UIFont.systemFont(ofSize: 12)
addSubview(textField)
}
override func layoutSubviews() {
super.layoutSubviews()
textField.frame.size = CGSize(width: frame.width - 20, height: 30)
textField.frame.origin = CGPoint(x: 10, y: 10)
}
}
Программный макет с автоматическим макетом
Вы также можете реализовать макет с помощью автоматического макета в коде. Поскольку я делаю это не часто, не буду приводить пример. Вы можете найти примеры реализации Auto Layout в коде на Stack Overflow и в других местах в Интернете.
Программные макеты
Существуют платформы с открытым исходным кодом, которые реализуют макет в коде. Меня интересует LayoutKit, но я не пробовал . Его написала команда разработчиков LinkedIn. Из репозитория Github: «LinkedIn создал LayoutKit, потому что мы обнаружили, что Auto Layout недостаточно эффективен для сложных иерархий представлений в прокручиваемых представлениях».
Зачем ставить fatalErrorвinit(coder:)
При создании подклассов UIView, которые никогда не будут использоваться в раскадровке или пере, вы можете ввести инициализаторы с другими параметрами и требованиями инициализации, которые не могут быть вызваны init(coder:)методом. Если вы не завершили init (coder :) с ошибкой fatalError, это может привести к очень запутанным проблемам в будущем, если вы случайно будете использовать его в раскадровке / пере. FatalError подтверждает эти намерения.
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
Если вы хотите запустить какой-либо код при создании подкласса независимо от того, создан ли он в коде или раскадровке / пере, вы можете сделать что-то вроде следующего (на основе ответа Джеффа Гу Канга )
class CustomView: UIView {
override init (frame: CGRect) {
super.init(frame: frame)
initCommon()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initCommon()
}
func initCommon() {
}
}