То, о чем вы спрашиваете, не является тривиальным использованием UIKit. В SwiftUI стили представлений являются декларативными, но с использованием шаблона Builder, где каждый модификатор представления возвращает представление, чтобы вы могли объединить настройки. Тем не менее, вы специально спросили о возможности настройки представлений, передав замыкание с, см. Решение 2 ниже. Но сначала я хотел представить другой подход, используя ArrayLiterals с перечислениями, см. Решение 1.
Решение 1 - Представление Composer
Представление Composer является библиотека (которую я разработал несколько лет go) для объявления представлений с использованием литералов массива перечислений, которая позволяет объявлять представления следующим образом:
let button: UIButton = [.color(.red), .text("Red"), .textColor(.blue)]
let label: UILabel = [.text("Hello World"), .textColor(.red)]
lazy var emailField: UITextField = [.font(.big), .height(50), .placeholder("Email"), .delegate(self)]
Прокрутите вниз до в нижней части README и вы увидите список поддерживаемых представлений , большинство классов представлений поддерживаются.
Принцип работы View Composer слишком сложен для публикации здесь, но взгляните на код!
Решение 2 - Zhip
В моем приложении с открытым исходным кодом iOS Zilliqa Wallet под названием Zhip Я создал еще одно решение для простой настройки UIViews, очень похожее на ваш вопрос.
Вот здесь ReceiveView , который выглядит следующим образом
Имея этот код:
final class ReceiveView: ScrollableStackViewOwner {
private lazy var qrImageView = UIImageView()
private lazy var addressTitleLabel = UILabel()
private lazy var addressValueTextView = UITextView()
private lazy var copyMyAddressButton = UIButton()
private lazy var addressAndCopyButton = UIStackView(arrangedSubviews: [addressValueTextView, copyMyAddressButton])
private lazy var addressViews = UIStackView(arrangedSubviews: [addressTitleLabel, addressAndCopyButton])
private lazy var requestingAmountField = FloatingLabelTextField()
private lazy var requestPaymentButton = UIButton()
// MARK: - StackViewStyling
lazy var stackViewStyle = UIStackView.Style([
qrImageView,
addressViews,
requestingAmountField,
.spacer,
requestPaymentButton
])
override func setup() {
setupSubviews()
}
}
и конфигурация представлений:
private typealias € = L10n.Scene.Receive
private extension ReceiveView {
// swiftlint:disable:next function_body_length
func setupSubviews() {
qrImageView.withStyle(.default)
addressTitleLabel.withStyle(.title) {
$0.text(€.Label.myPublicAddress)
}
addressValueTextView.withStyle(.init(
font: UIFont.Label.body,
isEditable: false,
isScrollEnabled: false,
// UILabel and UITextView horizontal alignment differs, change inset: stackoverflow.com/a/45113744/1311272
contentInset: UIEdgeInsets(top: 0, left: -5, bottom: 0, right: -5)
)
)
copyMyAddressButton.withStyle(.title(€.Button.copyMyAddress))
copyMyAddressButton.setHugging(.required, for: .horizontal)
addressAndCopyButton.withStyle(.horizontal)
addressViews.withStyle(.default) {
$0.layoutMargins(.zero)
}
requestingAmountField.withStyle(.decimal)
requestPaymentButton.withStyle(.primary) {
$0.title(€.Button.requestPayment)
}
}
}
Давайте go через конфигурацию некоторых представлений:
Конфигурируем UILabel
с именем addressTitleLabel
с помощью этого кода :
addressTitleLabel.withStyle(.title) {
$0.text(€.Label.myPublicAddress)
}
€
- это просто локальные typealias для контекста локализации для переведенных строк с ключом L10n.Scene.Receive.Label.myPublicAddress
, поэтому для устройства iOS с Engli sh настройка языка, которая будет переводить в строку "My public address"
.
.withStyle(.title)
- это вызов функции с именем withStyle
, которую я объявил в UILabel
, см. код на Github здесь , являющийся:
@discardableResult
func withStyle(
_ style: UILabel.Style,
customize: ((UILabel.Style) -> UILabel.Style)? = nil
) -> UILabel {
translatesAutoresizingMaskIntoConstraints = false
let style = customize?(style) ?? style
apply(style: style)
return self
}
Мы передаем .title
в качестве аргумента функции, и в объявлении функции выше вы можете видеть, что типом является UILabel.Style
, что означает, что мы объявили переменную stati c с именем title
как расширение на UILabel.Style
, являющееся неким стилем по умолчанию. Это несколько похоже на Шрифт SwiftUI, в котором есть регистр enum, называемый title
(но я создал его задолго до выхода SwiftUI
?). Где в случае SwiftUI это предустановка Font
, где, как и в моем случае, это предустановка всего UILabel.Style
. Давайте посмотрим на это!
UILabel.Style
, здесь title
:
static var title: UILabel.Style {
return UILabel.Style(
font: UIFont.title
)
}
Так что это просто вызов инициализатора со значением UIFont.title
в качестве шрифта.
Настроить блок - в функции withStyle
вторым аргументом является замыкающее замыкание, являющееся замыканием для настройки предустановленного стиля. В случае addressTitleLabel
здесь мы устанавливаем свойство text
для UILabel
.
Мульти-настройка в замыкании - в другом представлении - UnlockAppWithPincodeView
мы выполняем несколько настроек UILabel
:
func setupSubviews() {
descriptionLabel.withStyle(.body) {
$0
.text(€.label)
.textAlignment(.center)
}
}
Как применяются стили: Ранее выше мы видели код для
withStyle
, который вызывает
apply(style: style)
перед возвратом представления (UILabel). Это где наш взгляд получает стиль. Что делает именно то, что вы ожидаете, он применяет каждую конфигурацию:
extension UILabel {
func apply(style: Style) {
text = style.text
font = style.font ?? UIFont.Label.body
textColor = style.textColor ?? .defaultText
numberOfLines = style.numberOfLines ?? 1
textAlignment = style.textAlignment ?? .left
backgroundColor = style.backgroundColor ?? .clear
if let minimumScaleFactor = style.adjustsFontSizeMinimumScaleFactor {
adjustsFontSizeToFitWidth = true
self.minimumScaleFactor = minimumScaleFactor
}
}
}
Затем я применил этот шаблон для каждого представления UIKit, которое я хотел бы поддержать. Это наверняка некая стандартная копия (в вышеупомянутой ViewComposer
lib я приложил еще больше усилий для создания протоколов мостов и т. Д. c, но это также привело к гораздо более сложной базе кода). Пожалуйста, взгляните на каталог в Zhip, где находится весь этот код - ../Source/Extensions/UIKit
.
Особенно благодаря предварительным настройкам stati c для каждого стиля этого приводит к довольно аккуратному и короткому синтаксису для создания и оформления UIViews.