SwiftUI骨架动画异常上下弹跳,需仅实现淡入淡出效果
SwiftUI骨架视图弹跳问题解决
问题
开发SwiftUI骨架加载视图时,期望骨架在内容加载完成前仅循环执行淡入淡出动画,但实际运行时,骨架视图在淡入淡出的同时会出现上下弹跳。移除代码中的Spacer()能减少垂直动画幅度,但无法彻底解决问题。
原因
当前的动画被应用在整个Rectangle视图上,SwiftUI默认动画会影响所有可动画属性(包括布局相关属性)。再结合VStack和Spacer的布局特性,动画触发时视图布局会被重新计算,从而产生弹跳效果。核心问题是没有将动画仅限制在透明度变化上,导致布局属性被意外带动。
解决方案
- 精准控制动画作用范围:只对
opacity属性应用动画,避免影响布局 - 统一骨架视图与加载完成后内容的布局参数,消除布局切换时的波动
修改后的FadingSkeletonView
struct FadingSkeletonView: View { @State private var opacity: Double = 1.0 var body: some View { Rectangle() .foregroundColor(.gray) .cornerRadius(10) .opacity(opacity) .onAppear { withAnimation(.easeInOut(duration: 0.5).repeatForever(autoreverses: true)) { opacity = 0.3 } } } }
调整ProjectDashboardView布局
确保骨架视图和加载完成后的视图拥有完全一致的padding、frame等布局属性,同时替换Spacer()避免布局波动:
import SwiftUI struct FadingSkeletonView: View { @State private var opacity: Double = 1.0 var body: some View { Rectangle() .foregroundColor(.gray) .cornerRadius(10) .opacity(opacity) .onAppear { withAnimation(.easeInOut(duration: 0.5).repeatForever(autoreverses: true)) { opacity = 0.3 } } } } struct ProjectDashboardView: View { let project: Project? var body: some View { VStack(spacing: 0) { // 明确spacing消除默认布局差异 if let unwrappedProject = project { if let url = unwrappedProject.imageUrl { AsyncImage(url: url) { image in image.resizable() } placeholder: { ProgressView() } .aspectRatio(contentMode: .fill) .frame(height: 250) .cornerRadius(10) .clipped() .padding() } else { Rectangle() .foregroundColor(.gray) .frame(height: 250) .cornerRadius(10) .padding() } Text(unwrappedProject.title) .font(.largeTitle) .fontWeight(.bold) .padding([.leading, .trailing]) // 和骨架视图保持一致的水平padding } else { FadingSkeletonView() .frame(height: 250) .padding() FadingSkeletonView() .frame(height: 40) .padding([.leading, .trailing]) } } .frame(maxHeight: .infinity, alignment: .top) // 替代Spacer实现内容置顶,避免布局波动 .padding() } }
说明
- 用
withAnimation直接控制opacity值变化,确保动画仅作用于透明度,完全隔离布局属性 - 统一加载前后视图的padding参数,设置
VStack(spacing: 0)消除布局差异 - 用
.frame(maxHeight: .infinity, alignment: .top)替代Spacer(),既保留内容置顶效果,又避免Spacer带来的布局动画干扰
内容的提问来源于stack exchange,提问作者Gaz
相关产品推荐
相关产品推荐

