SwiftUI如何为frame的maxHeight: .infinity添加动画?
问题描述
我简化后的代码如下:
VStack { View1() View2() .frame(maxHeight: .infinity) } struct View1: View { @State private var animate = false var body: some View { Circle() .frame(width: animate ? 100 : 200, height: animate ? 100 : 200) .onTapGesture { animate.toggle() } .animation(.easeInOut, value: animate) } } struct View2: View { var body: some View { Color.red } }
当上方的View1完成动画、尺寸变化后,我希望给下方View2的frame添加动画效果。我试过下面的写法,虽然能实现动画,但View2内部的所有元素也会跟着一起动画,这不是我想要的效果:
View2() .animation(.easeInOut)
解决方案
要实现只让View2的frame动画、内部元素不受影响,你可以把frame动画的作用范围限制在一个容器视图上,让View2作为这个容器的子视图。这样动画只会作用于容器的frame,不会渗透到View2内部。
更合理的做法是把View1的状态提升到父视图,让父视图直接监听状态变化来触发容器动画,避免直接访问子视图内部状态:
struct ParentView: View { @State private var animate = false var body: some View { VStack { View1(animate: $animate) // 用透明容器承载frame动画,View2通过overlay嵌入 Color.clear .frame(maxHeight: .infinity) .animation(.easeInOut, value: animate) .overlay(View2()) } } } struct View1: View { @Binding var animate: Bool var body: some View { Circle() .frame(width: animate ? 100 : 200, height: animate ? 100 : 200) .onTapGesture { animate.toggle() } .animation(.easeInOut, value: animate) } } struct View2: View { var body: some View { Color.red } }
原理很简单:.animation修饰符会作用于当前视图及其所有子视图的可动画属性变化。把动画放在透明容器上,再通过overlay放置View2,View2就不会继承这个动画修饰符,只有容器的frame会产生动画效果,View2内部元素完全不受影响。
内容的提问来源于stack exchange,提问作者Nick Value
相关产品推荐
相关产品推荐

