Комментарии 12
В Кикстартере для стилей используют линзы, выглядит примерно так:
public func cardStyle <V: UIViewProtocol> (cornerRadius radius: CGFloat = Styles.cornerRadius) -> ((V) -> V) {
return roundedStyle(cornerRadius: radius)
<> V.lens.layer.borderColor .~ UIColor.ksr_grey_500.cgColor
<> V.lens.layer.borderWidth .~ 1.0
<> V.lens.backgroundColor .~ .white
}
пример использования:
_ = self.cardView
|> cardStyle()
|> dropShadowStyle()
|> UIView.lens.layer.borderColor .~ UIColor.ksr_navy_500.cgColor
Выглядит достаточно элегантно и возможности композиции на очень хорошем уровне.
Библиотека, позволяющая такие чудеса, называется Kickstarter-Prelude.
Концепция линз взята из функционального программирования, широко используется в Хаскеле (см. lens package).
На Свифте, из-за синтаксических особенностей, выглядит не так красиво, но достаточно неплохо.
Также, Хаскель позволяет генерировать код для линз автоматически (используя Template Haskell), а тут приходится писать их вручную. Но, поскольку Kickstarter для нас уже постарался, можно использовать готовые.
Около полугода назад опубликовал на GitHub решение для стилизации UIView
/NSView
, (микро-) фреймворк StyleSheet — идея перекликается со статьёй.
Стили ассоциируются с (пустыми) протоколами-маркерами и привязываются к подклассам UIView
/NSView
через protocol conformance:
// Style-marker protocols
protocol BodyFontStyle {}
protocol MultilineLabelStyle {}
func appStyle(palette p: PaletteProtocol) -> StyleProtocol {
return StyleSheet(styles: [
// Styles implementation for different base-classes.
Style<BodyFontStyle, UILabel> { $0.font = p.font.body },
Style<BodyFontStyle, UITextField> { $0.font = p.font.body },
Style<BodyFontStyle, UITextView> { $0.font = p.font.body },
Style<MultilineLabelStyle, UILabel> {
$0.numberOfLines = 0
$0.lineBreakMode = .byWordWrapping
},
])
}
final class BodyLabel: UILabel, BodyFontStyle, MultilineLabelStyle {}
// Perform on app initialization
try! RootStyle.autoapply(style: appStyle(palette: DefaultPalette())) // Specify `mode: .appearance` to use `UIAppearance`-hitchhiking
Таблицы стилей могут каскадироваться. Что такое "стиль" и "таблица стилей" описано в Style.swift.
Автоматическое применение стилей реализуется одним из двух механизмов, на выбор: через swizzling или через UIAppearance
-hitchhiking (см. RootStyle.swift). В обоих случаях применение стилей происходит так же, как при использовании UIAppearance
(доступно для iOS и tvOS).
Автоматическое применение использовать не обязательно, но удобно. Установка через Carthage и CocoaPods.
Используется в production и приносит пользу :)
Не вполне ясно, о чем вопрос. В примере выше есть BodyLabel, подкласс UIView с двумя стилями. Очевидно, вы можете изменить декларацию этого подкласса, если имеете доступ к коду. Вы также можете изменить реализацию стилей.
Можно добавить дополнительные стили (protocol conformance) через extension.
Если вопрос об изменении внешнего вида компонента во время выполнения, то эта задача решается несколько другими способами, независимо от используемого механизма стилизации.
Независимо от того, стилизуете ли вы компонент через Interface Builder, из кода непосредственно, через UIAppearance
или с помощью какого-то фреймворка, компонент, который изменяет свой внешний вид, должен иметь параметры отображения для каждого своего состояния.
К примеру, если у вас есть on/off button, то у неё должны быть свойства onColor
и offColor
. Вы можете задать им нужные значения любым доступным способом, а кнопка сама будет выбирать, цветом из какого свойства покраситься :)
При назначении свойст лейблу опечатка, повторно используется labelNormal, вместо labelTitle.
Спасибо за статью!
Swift Generics: cтили для UIView и не только #1