Matched Geometry Effects v.2
Рассмотрим еще один пример анимации, который имитирует раскрытие обложки проигрываемой композиции в Apple Music:
Для этого нам понадобиться свойство, отвечающее за размер изображения. При этом размер будет меняться в зависимости от значения логического свойства isZoomed
. В том случае, если оно будет принимать значение true
, то размер изображение будет 300 на 300 поинтов, а иначе по 44 поинта с каждой стороны:
struct ContentView: View {
@Namespace private var animation
@State private var isZoomed = false
var imageFrame: CGFloat {
isZoomed ? 300 : 44
}
var body: some View {
Text("Hello, World!")
}
}
Теперь выполним расстановку элементов в зависимости от значения логического свойства:
var body: some View {
VStack {
Spacer()
VStack {
HStack {
RoundedRectangle(cornerRadius: 10)
.fill(Color(.red))
.frame(width: imageFrame, height: imageFrame)
.padding(.top, isZoomed ? 20 : 0)
if !isZoomed {
Text("Artist - Song")
.font(.headline)
.matchedGeometryEffect(id: "TrackTitle", in: animation)
Spacer()
}
}
}
}
}
В качестве изображения у нас служит квадрат со скругленными углами, который мы поместили в горизонтальный стек вместе с названием музыкальной композиции. При этом текст будет отображаться только в том случае, если обложка композиции не раскрыта. Сам горизонтальный стек помещен в вертикальный стек, который в свою очередь находится так в вертикальном стеке.
Сразу после горизонтального стека создаем условие, при котором текст будет отображаться в вертикальном стеке, если обложка раскрыта:
if isZoomed {
Text("Artist - Song")
.font(.headline)
.matchedGeometryEffect(id: "TrackTitle", in: animation)
.padding(.bottom, 60)
}
Теперь нам надо проработать логику раскрытия музыкальной композиции по тапу. Для этого вызовем модификатор .onTapGesture
у внутреннего вертикального стека:
.onTapGesture {
withAnimation(.spring()) {
self.isZoomed.toggle()
}
}
И еще несколько модификаторов, для настройки внешнего вида вертикального стека:
.padding()
.frame(maxWidth: .infinity)
.frame(height: isZoomed ? 400 : 60)
.background(Color(white: 0.9))
В итоге тело свойства body
выглядит так:
var body: some View {
VStack {
Spacer()
VStack {
HStack {
RoundedRectangle(cornerRadius: 10)
.fill(Color(.red))
.frame(width: imageFrame, height: imageFrame)
.padding(.top, isZoomed ? 20 : 0)
if !isZoomed {
Text("Artist - Song")
.font(.headline)
.matchedGeometryEffect(id: "TrackTitle", in: animation)
Spacer()
}
}
if isZoomed {
Text("Artist - Song")
.font(.headline)
.matchedGeometryEffect(id: "TrackTitle", in: animation)
.padding(.bottom, 60)
}
}
.onTapGesture {
withAnimation(.spring()) {
self.isZoomed.toggle()
}
}
.padding()
.frame(maxWidth: .infinity)
.frame(height: isZoomed ? 400 : 60)
.background(Color(white: 0.9))
}
}
Курсы по языку Swift, доступные каждому: LearnMeToo