SwiftUI中无状态值时如何替换废弃的.animation(.spring())?
解决SwiftUI废弃
.animation(.spring())的替代方案 SwiftUI 3.0之后,不带绑定值的.animation()修饰器被废弃,必须明确指定触发动画的依赖条件。你的mockupView虽然没有本地状态,但视图内容的变化完全依赖于传入的一系列参数(比如currentVisibleMockUpIndex、iPhoneSettings、screenshotImage等),可以用以下两种方式替换:
方案1:直接绑定所有触发变化的参数
把所有会导致MockupPreview内容更新的参数打包成一个元组,作为动画的触发值:
var mockupView: some View { Group { MockupPreview( iPhoneSettings: iPhoneSettings, rearIphoneSettings: rearIphoneSettings, overlaySettings: overlaySettings, iBackground: currentVisibleMockUpIndex, importedIBackground: importedBackground, importedLogo: $importedOverlay, opacityVignette: opacityVignette, backgroundHue: backgroundHue, backgroundSaturation: backgroundSaturation, backgroundBlur: backgroundBlur, backgroundBlurAmmount: backgroundBlurAmmount, backgroundColor: backgroundColor, bgColor: bgColor, screenshotImage: screenshotImage, importedBackgroundImage: importedBackgroundImage, gridVisible: gridVisible, accentColor: accentColor ) .mask(RoundedRectangle(cornerRadius: 10)) .frame(width: screenWidth, height: screenWidth) .padding(.bottom) // 替换成带依赖值的动画,元组里放所有影响视图的参数 .animation(.spring(), value: ( iPhoneSettings, rearIphoneSettings, overlaySettings, currentVisibleMockUpIndex, importedBackground, importedOverlay, opacityVignette, backgroundHue, backgroundSaturation, backgroundBlur, backgroundBlurAmmount, backgroundColor, bgColor, screenshotImage, importedBackgroundImage, gridVisible, accentColor )) } }
方案2:封装依赖为结构体(更整洁)
如果参数太多,元组看着杂乱,可以把这些依赖参数封装成一个遵循Equatable的结构体:
// 先定义一个包含所有依赖的结构体,要遵循Equatable struct MockupDependencies: Equatable { let iPhoneSettings: YourSettingsType // 替换成你实际的类型 let rearIphoneSettings: YourRearSettingsType let overlaySettings: YourOverlaySettingsType let currentVisibleMockUpIndex: Int let importedBackground: YourBackgroundType let importedOverlay: YourOverlayType let opacityVignette: Double let backgroundHue: Double let backgroundSaturation: Double let backgroundBlur: Bool let backgroundBlurAmmount: Double let backgroundColor: Color let bgColor: Color let screenshotImage: UIImage? // 根据你的实际类型调整,比如Image let importedBackgroundImage: UIImage? let gridVisible: Bool let accentColor: Color } // 然后在视图里用这个结构体 var mockupView: some View { // 把参数打包成结构体实例 let dependencies = MockupDependencies( iPhoneSettings: iPhoneSettings, rearIphoneSettings: rearIphoneSettings, overlaySettings: overlaySettings, currentVisibleMockUpIndex: currentVisibleMockUpIndex, importedBackground: importedBackground, importedOverlay: importedOverlay, opacityVignette: opacityVignette, backgroundHue: backgroundHue, backgroundSaturation: backgroundSaturation, backgroundBlur: backgroundBlur, backgroundBlurAmmount: backgroundBlurAmmount, backgroundColor: backgroundColor, bgColor: bgColor, screenshotImage: screenshotImage, importedBackgroundImage: importedBackgroundImage, gridVisible: gridVisible, accentColor: accentColor ) Group { MockupPreview( iPhoneSettings: dependencies.iPhoneSettings, rearIphoneSettings: dependencies.rearIphoneSettings, overlaySettings: dependencies.overlaySettings, iBackground: dependencies.currentVisibleMockUpIndex, importedIBackground: dependencies.importedBackground, importedLogo: $importedOverlay, opacityVignette: dependencies.opacityVignette, backgroundHue: dependencies.backgroundHue, backgroundSaturation: dependencies.backgroundSaturation, backgroundBlur: dependencies.backgroundBlur, backgroundBlurAmmount: dependencies.backgroundBlurAmmount, backgroundColor: dependencies.backgroundColor, bgColor: dependencies.bgColor, screenshotImage: dependencies.screenshotImage, importedBackgroundImage: dependencies.importedBackgroundImage, gridVisible: dependencies.gridVisible, accentColor: dependencies.accentColor ) .mask(RoundedRectangle(cornerRadius: 10)) .frame(width: screenWidth, height: screenWidth) .padding(.bottom) // 直接用结构体作为动画触发值 .animation(.spring(), value: dependencies) } }
注意点
- 所有放入
value的类型必须遵循Equatable协议,SwiftUI靠这个检测值变化来触发动画。如果是自定义类型,记得手动实现==方法。 - 如果只有部分参数会导致视图变化,只需要把这些参数放进
value里就行,不用全加,避免没必要的动画触发。
内容的提问来源于stack exchange,提问作者SeanKly
相关产品推荐
相关产品推荐

