Зачем нужны нестандартные фигуры (Shapes) в самых обычных SwiftUI View?
Давайте сразу к делу. Есть такой макет.
Не буду подробно останавливаться на верстке, весьма обычный элемент.
Высота верхней половины динамическая, зависит от наполнения и, в частности, от рисунка внутри.
Верхнюю и нижнюю половины поместим в 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() // <= здесь
Результат будет тот же:
На этом все!✌🏻