SwiftUI 4/iOS 16中Asymmetric Transition行为是否发生变化?
iOS 16中Asymmetric Transition与分页TabView联动异常修复
问题描述
在iOS 15中,基于分页TabView实现的联动不对称过渡动画运行正常:滑动切换页面时,顶部文本视图的动画方向能完全匹配页面滑动方向。但升级到iOS 16后,滑动几页再切换方向,会出现顶部视图的移除和插入动画来自同一边缘的异常,过渡效果不符合预期。
问题原因
iOS 16中SwiftUI的状态更新通知机制和动画触发逻辑发生了变化。原代码通过@Published属性的willSet观察者更新pageDirection,但在iOS 16中,selectedPage的@Published通知可能先于pageDirection的更新被SwiftUI捕获,导致过渡动画计算时使用的是旧的方向值,最终出现动画异常。
解决方案
通过自定义绑定同步更新选中页和滑动方向,确保状态变化与动画触发在同一上下文内完成,让SwiftUI能准确获取最新的方向值来计算过渡动画。
修改后代码示例
import SwiftUI class SharedStore: ObservableObject { @Published var selectedPage: Int = 0 var pageDirection: UIPageViewController.NavigationDirection = .forward } struct ContentView: View { @StateObject var sharedStore = SharedStore() var body: some View { VStack { Text("Page \(sharedStore.selectedPage)") .id(sharedStore.selectedPage) .frame(maxWidth: UIScreen.main.bounds.width) .transition( .asymmetric( insertion: .move(edge: sharedStore.pageDirection == .forward ? .trailing : .leading), removal: .move(edge: sharedStore.pageDirection == .forward ? .leading : .trailing) ) ) // 使用自定义绑定替代直接绑定@Published属性 TabView(selection: Binding( get: { sharedStore.selectedPage }, set: { newValue in withAnimation(.easeInOut) { // 先更新方向,再更新选中页 sharedStore.pageDirection = newValue > sharedStore.selectedPage ? .forward : .reverse sharedStore.selectedPage = newValue } } )) { ForEach(0..<10, id:\.self) { index in Text("Hello \(index)") } } .tabViewStyle(.page) } .padding() } }
方案说明
- 移除
SharedStore中selectedPage的willSet观察者,将方向判断逻辑移到自定义绑定的set方法中。 - 使用
withAnimation包裹状态更新操作,确保pageDirection和selectedPage的变化被SwiftUI同时捕获,动画上下文能获取到最新的方向参数,从而生成正确的不对称过渡效果。
内容的提问来源于stack exchange,提问作者skegget
相关产品推荐
相关产品推荐

