Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Несмотря на то, что UIKit постепенно уступает место более современному во всех отношениях SwiftUI, до сих пор остается огромное количество проектов, которые основаны на фреймворке UIKit. Далее будет представлена библиотека, которая позволяет выполнять конструирование внешнего вида намного быстрее и удобнее, чем стандартные средства.
Реализация
В сети интернет можно найти огромное количество решений на данную тему, как от известных и солидных компаний, так и от отдельных разработчиков. Тем не менее, на мой взгляд, все существующие решения перегружены так называемым синтаксическим сахаром. Например, нет никакой необходимости в использовании closure в библиотеке SpanKit. Или объявлять дополнительный инициализатор для UIView в PureLayout.
По этой причине было разработано более простое и легковесное решение для создания constraints.
import UIKit
protocol LayoutItem {
func constraint(_ attribute: NSLayoutConstraint.Attribute,
_ relation: NSLayoutConstraint.Relation,
to target: LayoutItem?,
_ targetAttribute: NSLayoutConstraint.Attribute?,
multiplier: CGFloat,
constant: CGFloat) -> NSLayoutConstraint
}
extension LayoutItem {
func constraint(_ attribute: NSLayoutConstraint.Attribute,
_ relation: NSLayoutConstraint.Relation = .equal,
to target: LayoutItem? = nil,
_ targetAttribute: NSLayoutConstraint.Attribute? = nil,
multiplier: CGFloat = 1,
constant: CGFloat = 0) -> NSLayoutConstraint {
return NSLayoutConstraint(
item: self,
attribute: attribute,
relatedBy: relation,
toItem: target,
attribute: targetAttribute ?? attribute,
multiplier: multiplier,
constant: constant
)
}
}
// MARK: - UIView+LayoutItem
extension UIView: LayoutItem {}
// MARK: - UILayoutGuide+LayoutItem
extension UILayoutGuide: LayoutItem {}
Такое решение было выбрано в пользу стандартной библиотеки, а если быть точнее, то синтезированы на основе методов constraint(equalTo:) и подобных для NSLayoutAnchor. И с учетом уклона swift в сторону протокольно-ориентированного программирования.
Таким образом верстка экрана выглядит следующим образом.
NSLayoutConstraint.activate([
scrollView.constraint(.top, to: view, .top),
scrollView.constraint(.leading, to: view, .leading),
scrollView.constraint(.bottom, to: view, .bottom),
scrollView.constraint(.trailing, to: view, .trailing),
scrollView.contentLayoutGuide.constraint(.width, to: view),
stackView.constraint(.top, to: scrollView.contentLayoutGuide, .top),
stackView.constraint(.leading, .greaterThanOrEqual, to: scrollView.contentLayoutGuide, .leading),
stackView.constraint(.leading, to: view, .leadingMargin),
stackView.constraint(.bottom, to: scrollView.contentLayoutGuide, .bottom),
stackView.constraint(.trailing, .lessThanOrEqual, to: scrollView.contentLayoutGuide, .trailing),
stackView.constraint(.trailing, to: view, .trailingMargin)
])
Внимательный читатель может отметить, как правильно верстать UIScrollView с системными отступами для каждого устройства без создания вложенного containerView.
Заключение
Каждый раз, когда возникает вопрос о разработке какого-либо решения, не стоит забывать о такой важной метрике, как скорость разработки, сложность поддержки существующего решения и возможность его расширения. Представленное решение по каждому из этих пунктов превосходит практически все известные библиотеки.
Ссылки
SnapKit
PureLayout
Stevia