修改Popover内容出现异常重载滚动动画而非平滑过渡
开发Popover时,需要根据上方选项动态展开内容,期望实现无动画或平滑展开效果,但实际选择Menu内选项后,Popover出现类似嵌套滚动视图的菜单重载动画。奇怪的是用普通Button修改状态时不会触发这个问题,尝试添加.id()修饰符、通过opacity/frame控制内容显隐都无法解决。

原代码如下:
struct DropdownTestView: View { @State var presentPopover: Bool = false @State var choice: Int = 0 var body: some View { VStack { Button { presentPopover = true } label: { Text("Press To Choose") } .popover(isPresented: $presentPopover) { popoverView .padding() } Spacer() } .padding() } var popoverView: some View { VStack(alignment: .leading) { Divider() Menu { ForEach(0..<6) { num in Button { choice = num } label: { Text("\(num)") } } } label: { Text("Make A Choice") } if choice != 0 { Divider() HStack { Text("WRONG CHOICE") } } } .frame(width: 220) } }
之前尝试过的无效写法:
HStack { Text("WRONG CHOICE") } .opacity(choice != 0 ? 1.0 : 0) .frame(height: choice != 0 ? 30 : 0)
问题根源
Menu组件内部自带动画逻辑,当它修改外部@State变量时,会将自身的动画上下文传递给Popover的视图更新流程,导致整个Popover内容触发不必要的滚动/重载动画,而普通Button不会携带这种额外的动画上下文。
解决方案
方案1:修改状态时禁用动画
在Menu内的Button动作里,用withAnimation(.none)包裹状态修改,切断Menu的动画传递:
Menu { ForEach(0..<6) { num in Button { withAnimation(.none) { choice = num } } label: { Text("\(num)") } } } label: { Text("Make A Choice") }
方案2:给动态内容禁用事务动画
给需要动态显示的内容添加.transaction修饰符,强制取消动画:
if choice != 0 { Divider() HStack { Text("WRONG CHOICE") } .transaction { transaction in transaction.animation = nil } }
两种方案都能解决问题,选择哪种取决于你的需求:如果希望所有状态更新都不带动画,用方案1;如果只针对动态内容取消动画,用方案2。
内容的提问来源于stack exchange,提问作者CalebK
相关产品推荐
相关产品推荐

