Предыстория
Недавно я захотел перенести своё мини-приложение WeChat "Вызов лепестковых слов" на iOS. В этой игре вы составляете слова, нажимая на буквы на лепестках. Рисовать лепестки в CSS было просто, но при переходе на SwiftUI возникли сложности.
Мои знания SwiftUI довольно поверхностны - до этого я создал лишь несколько простых приложений. Я не знал, с чего начать рисование лепестка. Поискав "SwiftUI лепесток" в Google, я нашёл эту статью. Хотя решение там было не совсем тем, что я хотел, оно дало отправную точку.
Что такое Shape Protocol?
Проще говоря, Shape Protocol в SwiftUI - это инструмент для создания собственных фигур. Вам нужно реализовать метод path(in rect: CGRect) -> Path
, который определяет, как рисовать фигуру.
Первая попытка: Рисование дуг с помощью addArc
В статье использовался метод addArc
:
struct DaisyPental: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.minX, y: rect.midY))
path.addArc(
center: CGPoint(x: rect.maxX, y: rect.midY),
radius: rect.maxX*(1/11),
startAngle: .degrees(90),
endAngle: .degrees(270),
clockwise: true
)
return path
}
}
Чтобы понять код, я протестировал его в Xcode с красным фоном:
struct ShapTest: View {
var body: some View {
DaisyPental()
.fill(.yellow.gradient)
.frame(width: 110, height: 20)
.background(.red) // Красный фон для наглядности
}
}
Система координат SwiftUI неинтуитивна
Важное замечание:
- Начало координат вверху слева: Не внизу
- Ось X: Положительное направление вправо (нормально)
- Ось Y: Положительное направление вниз (неинтуитивно!)
Следовательно:
rect.minX
,rect.minY
→ Верхний левый уголrect.maxX
,rect.maxY
→ Нижний правый уголrect.midX
,rect.midY
→ Центр
Экспериментируйте с изменением значений в path.move
, наблюдая превью в Xcode.
Углы в addArc ещё более неинтуитивны
Определение углов в addArc
особенное:
- 0° → Вправо
- 90° → Вниз (Не вверх!)
- 180° → Влево
- 270° → Вверх
Это отличается от стандартной математической системы координат.
addQuadCurve: Инструмент для кривых
Я понял, что addArc
не подходит для лепестка. Увидев addQuadCurve
на YouTube, я попробовал его:
path.addQuadCurve(
to: CGPoint, // Конечная точка
control: CGPoint // Контрольная точка
)
- Начальная точка: Текущее положение
- Конечная точка: Куда должна идти кривая
- Контрольная точка: Определяет кривизну
Изменение контрольной точки визуально меняет кривую.
Моя финальная реализация лепестка
После экспериментов я получил эту форму:
import SwiftUI
struct PetalShape: Shape {
func path(in rect: CGRect) -> Path {
Path { path in
// Начальная точка
path.move(to: CGPoint(x: rect.minX + 30, y: rect.minY + 30))
// Левая кривая лепестка
path.addQuadCurve(
to: CGPoint(x: rect.minX + 30, y: rect.minY - 30),
control: CGPoint(x: rect.minX - 10, y: rect.minY)
)
// Кончик лепестка
path.addQuadCurve(
to: CGPoint(x: rect.maxX * 1.8, y: rect.minY),
control: CGPoint(x: rect.midX + 40, y: -rect.maxY + 30)
)
// Правая сторона (возврат к началу)
path.addQuadCurve(
to: CGPoint(x: rect.minX + 30, y: rect.minY + 30),
control: CGPoint(x: rect.midX + 40, y: rect.maxY - 30)
)
}
}
}
Пример использования:
struct ShapeTest: View {
var body: some View {
PetalShape()
.fill(.yellow.gradient)
.frame(width: 110, height: 110)
}
}
Следующий шаг: Сборка целого цветка
С одним лепестком собрать цветок просто:
- Дублируйте несколько лепестков
- Поворачивайте с помощью
rotationEffect
- Настраивайте положение через
offset
- Собирайте в целый цветок
Извлечённые уроки
Ключевые выводы:
- Система координат: Особенно неинтуитивна
- addQuadCurve > addArc: Лучше для естественных кривых
- Контрольная точка критична: Эксперименты необходимы
- Превью незаменимо: Постоянно используйте Canvas
В заключение
Я создал форму лепестка и продолжаю разработку "Вызова лепестковых слов" для iOS, планируя скорый релиз.
Написал эту статью, чтобы задокументировать процесс. Если вы работаете с кастомными фигурами в SwiftUI, надеюсь, это поможет!