Зачем нужны нестандартные фигуры (Shapes) в самых обычных SwiftUI View?

Alex Kraev
3 min readFeb 7, 2023

--

Всем привет! Давайте сразу к делу.

Есть такой макет.

Не буду подробно останавливаться на верстке, весьма обычный элемент.

Высота верхней половины динамическая, зависит от наполнения и, в частности, от рисунка внутри.

Верхнюю и нижнюю половины поместим в VStack, цвет у верхней выкрасим через ZStack, серую рамку вокруг сделаем через .background:

VStack {
ZStack {
Rectangle()
.fill(.indigo.opacity(0.4))

}
VStack {

}

}.background(
RoundedRectangle(cornerRadius: 16)
.stroke(.gray, lineWidth: 1)
)

Выход цветной подложки сверху за пределы рамки классически исправляем через .cornerRadius(16):

VStack {

}.background(
RoundedRectangle(cornerRadius: 16)
.stroke(.gray, lineWidth: 1)
)
.cornerRadius(16) // <= здесь

Итоговый результат действительно совпадает с макетом:

И, казалось бы, все хорошо, но позже дизайнер предложил смещать вертикально рисунок, чтобы картинка специально выходила за пределы рамки. Ну что ж, добавим .offset(y: …) к изображению рисунка:

И вот сталкиваемся с сайд-эффектом модификатора .cornerRadius(): он обрезает вью, к которому он применяется.

Ок, ситуацию исправило бы применение .cornerRadius не ко всему вью, а только к ZStack с цветом:

ZStack { 
Rectangle()
.fill(.indigo.opacity(0.4))
.cornerRadius(16) // <= здесь

}

Но тогда закругляются и нижние углы у прямоугольника:

Значит нужен прямоугольник, у которого можно было бы настроить, какие углы закруглять. Из коробки такого нет. Отрисуем сами! Библиотеку с новой и другими фигурами можно найти здесь.

Применим расширение для View, построенного вокруг нового shape, для этого импортируем библиотеку:

import Shapes


ZStack {
Rectangle()
.fill(.indigo.opacity(0.4))
.cornerRadius(16, corners: .tops) // <= здесь

}

И вот теперь все хорошо:

А если нужен кроп, то применим модификатор .clipped ко всей вью:

VStack {
ZStack {
Rectangle()
.fill(.indigo.opacity(0.4))
.cornerRadius(16, corners: .tops) // Здесь

}
VStack {

}

}.background(
RoundedRectangle(cornerRadius: 16)
.stroke(.gray, lineWidth: 1)
)
.clipped() // <= здесь

Результат будет тот же:

На этом все!✌🏻

Не забывайте подписываться на github и на канал в телеграмме, посвященный мобильной разработке.

--

--

Alex Kraev

Mobile engineer | IT lead | Writer | Open Source author from Moscow, like Swift, SwiftUI, Kotlin, Jetpack, subscribe to my channel: https://t.me/swiftui_dev