December 30, 2023
47. Изучаем тени в SwiftUI
Посмотрим как настраиваются тени в SwiftUI, заодно поработаем с выбором цвета и слайдерами.
Сделаем экран, на котором можно настроить все параметры тени и посмотреть на результат:
Сделаем свойство для получения случайного цвета:
extension Color {
static var random: Self {
Color(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1)
)
}
}
Теперь подготовим модель для параметров тени:
struct ShadowModel {
var color: Color
var radius: CGFloat
var x: CGFloat
var y: CGFloat
static var randomized: Self {
.init(
color: .random,
radius: CGFloat.random(in: 0...16),
x: CGFloat.random(in: -16...16),
y: CGFloat.random(in: -16...16)
)
}
}
Диапазон значений поставлен для примера, можете экспериментировать с любыми значениями.
Создадим цвет для модификатора с "карточкой", внутри которого будет применяться тень:
Сделаем сам модификатор для "карточки", который принимает на вход отступы для контента и параметры тени:
struct CardModifier: ViewModifier {
let padding: CGFloat
let shadowModel: ShadowModel
func body(content: Content) -> some View {
content
.padding(padding)
.background {
RoundedRectangle(cornerRadius: 12, style: .continuous)
.foregroundStyle(.cardBackground) // цвет из ассетов
.shadow(
color: shadowModel.color,
radius: shadowModel.radius,
x: shadowModel.x,
y: shadowModel.y
)
}
}
}
extension View {
func insideCard(
padding: CGFloat = 12,
shadowModel: ShadowModel
) -> some View {
modifier(
CardModifier(
padding: padding,
shadowModel: shadowModel
)
)
}
}
Сверстаем вьюшку с настройками:
Group {
ColorPicker( // <- а вот и выбор цвета
"Цвет тени",
selection: $shadowModel.color,
supportsOpacity: false
)
Divider()
VStack {
Slider(value: $shadowModel.radius, in: 0...16, step: 1)
Text("Радиус: \(makeRoundedText(for: shadowModel.radius))")
}
VStack {
Slider(value: $shadowModel.x, in: -16...16)
Text("Отступ по оси X: \(makeRoundedText(for: shadowModel.x))")
}
VStack {
Slider(value: $shadowModel.y, in: -16...16)
Text("Отступ по оси Y: \(makeRoundedText(for: shadowModel.y))")
}
Button("Randomize") {
withAnimation { shadowModel = .randomized }
}
.buttonStyle(.borderedProminent)
.padding(.top, 16)
}
.padding(.vertical, 4)
.padding(.horizontal)
}
struct ShadowExample: View {
@State private var shadowModel = ShadowModel.randomized
var body: some View {
VStack(spacing: 0) {
settingsView
Rectangle()
.frame(height: 125)
.foregroundStyle(.white)
.overlay(alignment: .bottom) {
Text("Light mode preview")
.insideCard(shadowModel: shadowModel)
.padding(.bottom)
}
Rectangle()
.ignoresSafeArea()
.overlay(alignment: .top) {
Text("Dark mode preview")
.insideCard(shadowModel: shadowModel)
.padding(.top)
.environment(\.colorScheme, .dark)
}
}
}
// остальной код
}
Код для этой статьи можно посмотреть тут, а другие статьи - тут.