Что такое дизайн-система?
Система дизайна (Design System) — это комплексный набор рекомендаций, компонентов и инструментов, которые используются для создания последовательных и целостных пользовательских интерфейсов на разных платформах и в разных продуктах. Она служит единым источником истины для дизайна и разработки, помогая командам поддерживать единый внешний вид и ощущение от своих продуктов.
В двух словах, дизай-система нужна нам для того, чтобы обеспечить единый внешний вид и восприятие различных продуктов на разных платформах, обеспечивая бесшовный пользовательский опыт.
Благодаря согласованности мы можем получить эффективность, которая ускоряет процесс проектирования и разработки за счет предоставления многократно используемых компонентов и шаблонов.
Улучшение сотрудничества между дизайнерами и разработчиками получается за счет предоставления общего языка и набора инструментов, уменьшения недопонимания и обеспечения согласованности.
OK, нам нужно внедрить систему проектирования в наш проект. Сделаем это на примере. Шаблон дизайна я взял из Figma Free Mobile App Template. Для этого проекта я выбрал приложение Podcast.
Для создания системы дизайна нам нужно создать такие основы, как цвет, типографика и интервалы.
Дизайн-система
Цвета
Для цвета я использую Ассеты, в которых объявляю все цвета, которые мне нужны, как на картинке ниже:
Затем мы создаем расширение для работы с цветовыми маркерами:
import SwiftUI public extension Color { static let accent1 = Color("Accent 1", bundle: .module) static let accent2 = Color("Accent 2", bundle: .module) static let accent3 = Color("Accent 3", bundle: .module) static let grayScale1 = Color("Grayscale 1", bundle: .module) static let grayScale2 = Color("Grayscale 2", bundle: .module) static let grayScale3 = Color("Grayscale 3", bundle: .module) static let grayScale4 = Color("Grayscale 4", bundle: .module) static let grayScale5 = Color("Grayscale 5", bundle: .module) }
Я знаю, что названия цветов все еще могут путаться, но пока мы просто создадим подобие Podcast App Guidelines. Мы можем использовать его следующим образом:
Color.accent1
Типографика
Для типографики нам нужно импортировать наш пользовательский шрифт в менеджер пакетов или проект:
После того как мы импортировали шрифт в наш проект, нам нужно создать класс и метод для регистрации пользовательского шрифта в приложении, это очень просто:
import SwiftUI public enum NotoSans: String, CaseIterable { case thin = "NotoSans-Thin" case bold = "NotoSans-Bold" case light = "NotoSans-Light" case black = "NotoSans-Black" case medium = "NotoSans-Medium" case regular = "NotoSans-Regular" case semiBold = "NotoSans-SemiBold" case extraBold = "NotoSans-ExtraBold" case extraLight = "NotoSans-ExtraLight" } public struct NotoSansFont { public static func registerFonts() { NotoSans.allCases.forEach { registerFont(bundle: .module, fontName: $0.rawValue, fontExtension: "ttf") } } fileprivate static func registerFont(bundle: Bundle, fontName: String, fontExtension: String) { guard let fontURL = bundle.url(forResource: fontName, withExtension: fontExtension), let fontDataProvider = CGDataProvider(url: fontURL as CFURL), let font = CGFont(fontDataProvider) else { fatalError("Couldn't ceate font from filename: \(fontName) with extension \(fontExtension)") } var error: Unmanaged<CFError>? CTFontManagerRegisterGraphicsFont(font, &error) } }
Объявите здесь все типы вашего шрифта, после чего создайте расширение для шрифта следующим образом:
import SwiftUI extension Font { public static var h1: Font = { return notoSans(.bold, size: 36) }() public static var h2: Font = { return notoSans(.semiBold, size: 24) }() public static var h3: Font = { return notoSans(.medium, size: 18) }() public static var h4: Font = { return notoSans(.medium, size: 14) }() public static var h5: Font = { return notoSans(.medium, size: 12) }() public static var h6: Font = { return notoSans(.regular, size: 12) }() public static func notoSans(_ font: NotoSans, size: CGFloat) -> Font { return .custom(font.rawValue, size: size) } }
Чтобы использовать шрифт, мы можем просто сделать так:
Text("Listen to the best Podcast") .font(.h1) .foregroundColor(.grayScale1)
Но мы можем еще больше упростить задачу с помощью ViewModifier:
struct TitleStyle: ViewModifier { func body(content: Content) -> some View { content.font(.h1) } } extension View { public func titleStyle() -> some View { modifier(TitleStyle()) } }
Тогда мы можем применить шрифт следующим образом:
Text("Listen to the best Podcast") .foregroundColor(.grayScale1) .titleStyle()
Интервалы
Для интервалов мы просто добавим следующее:
public enum Spacing { public static let small: CGFloat = 8 public static let medium: CGFloat = 16 public static let large: CGFloat = 32 public static let extrLarge: CGFloat = 64 }
Основание готово!
Далее мы перейдем к компонентам и просто создадим компонент кнопки.
Кнопка
В SwiftUI мы можем создать ButtonStyle, который может быть использован для всех кнопок.
Так как же его использовать?
На самом деле все очень просто, вы можете просто скопировать из моего кода:
import SwiftUI public struct PrimaryButtonStyle: ButtonStyle { public init() {} public func makeBody(configuration: Configuration) -> some View { configuration.label .font(.h4) .padding(Spacing.medium) .background(Capsule().fill(Color.accent1)) .foregroundColor(.white) .scaleEffect(configuration.isPressed ? 0.95 : 1.0) } }
А как это использовать? Следующим образом:
Button { } label: { Text("Create new account") } .buttonStyle(PrimaryButtonStyle())
Но мы можем сделать все более красивым, просто добавив такой код:
extension ButtonStyle where Self == PrimaryButtonStyle { public static var primary: Self { Self() } }
Поэтому всякий раз, когда вы регистрируете ButtonStyle, вы просто вызываете его следующим образом:
Button { } label: { Text("Create new account") } .buttonStyle(.primary)
Дайте мне 6 часов, чтобы срубить дерево, и первые 4 часа я потрачу на заточку топора.
Так и с дизайн-системой. Мы потратим 4 часа на заточку топора, это заняло больше половины времени, но это того стоило.