[英]Animate ViewBuilder content size change in SwiftUI
I am wondering how I can animate the content size of a ViewBuilder view.我想知道如何为 ViewBuilder 视图的内容大小设置动画。 I have this:
我有这个:
struct CardView<Content>: View where Content: View {
private let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
VStack(spacing: 0) {
content
.padding(16)
}
.background(.white)
.cornerRadius(14)
.shadow(color: .black.opacity(0.07), radius: 12, x: 0, y: 2)
}
}
I would like to animate any size changes to content
, but I can't find a nice way of doing this.我想为
content
的任何大小更改设置动画,但我找不到这样做的好方法。 I found two ways that work:我发现了两种可行的方法:
animation(.linear)
in CardView
works, but is deprecated and discouraged since I have no value
to attach the animation to.CardView
中使用animation(.linear)
是可行的,但由于我没有附加动画的value
,因此不推荐使用和不鼓励使用。withAnimation
inside content
when changing the content works, too, but I would like to encapsulate this behaviour in CardView
.content
时在内容中使用withAnimation
也可以,但我想将此行为封装在CardView
中。 CardView
is heavily reused and doing it in content
is easy to forget and also not where this behaviour belongs in my opinion. CardView
被大量重用,并且在content
中执行它很容易忘记,而且在我看来也不属于这种行为。 I also tried using GeometryReader
but could not find a good way of doing it.我也尝试过使用
GeometryReader
,但找不到一个好的方法。
Here is an approach for you:这是适合您的方法:
You may take look at this link as well:你也可以看看这个链接:
How to replace deprecated .animation() in SwiftUI?如何在 SwiftUI 中替换已弃用的 .animation()?
struct ContentView: View {
@State private var cardSize: CGSize = CGSize(width: 150, height: 200)
var body: some View {
VStack {
CardView(content: {
Color.red
.overlay(Image(systemName: "dollarsign.circle").resizable().scaledToFit().padding())
.onTapGesture {
cardSize = CGSize(width: cardSize.width + 50, height: cardSize.height + 50)
}
}, cardSize: cardSize)
}
}
}
struct CardView<Content>: View where Content: View {
let content: Content
let cardSize: CGSize
init(@ViewBuilder content: () -> Content, cardSize: CGSize) {
self.content = content()
self.cardSize = cardSize
}
var body: some View {
content
.frame(width: cardSize.width, height: cardSize.height)
.cornerRadius(14)
.padding(16)
.background(.white)
.shadow(color: .black.opacity(0.07), radius: 12, x: 0, y: 2)
.animation(.easeInOut, value: cardSize)
}
}
You might find this useful.您可能会发现这很有用。
It uses a looping animation and a user gesture for add size and resting.它使用循环动画和用户手势来增加尺寸和休息。
struct PilotTestPage: View {
@State private var cardSize = CGSize(width: 150, height: 200)
var body: some View {
return ZStack {
Color.yellow
CardView() {
Color.clear
.overlay(
Image(systemName: "dollarsign.circle")
.resizable()
.scaledToFit()
.padding()
)
}
.frame(
width: cardSize.width
,height: cardSize.height
)
.onTapGesture {
withAnimation {
cardSize = CGSize(
width: cardSize.width + 50
,height: cardSize.height + 50
)
}
}
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(.red)
.frame(
width: 200
,height: 44
)
.offset(y: -300)
.onTapGesture {
withAnimation {
cardSize = CGSize(
width: 150
,height: 200
)
}
}
}
.ignoresSafeArea()
}
struct CardView<Content>: View where Content: View {
let content: Content
init(
@ViewBuilder content: () -> Content
) {
self.content = content()
}
@State private var isAtStart = true
var body: some View {
ZStack {
content
.background(
RoundedRectangle(cornerRadius: 12)
.fill(.white)
.shadow(
color: .black.opacity(0.25)
,radius: 12
,x: 0
,y: 2
)
)
}
.scaleEffect(isAtStart ? 0.9 : 1.0)
.rotationEffect(.degrees(isAtStart ? -2 : 2))
.onAppear {
withAnimation(
.easeInOut(duration: 1)
.repeatForever()
) {
self.isAtStart.toggle()
}
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.