如何修改SwiftUI中redacted修饰符的shimmer闪烁效果颜色
SwiftUI redacted 闪烁效果透出原有底色解决方案
问题原因
SwiftUI 原生的 .redacted(.placeholder) 修饰符只会修改无自定义背景的视图的占位样式,已经设置了自定义 background 底色的视图会保留原有颜色,不会被占位样式覆盖,因此会出现底色透出的问题。
解决方案
方案1:父容器叠加蒙版(快速修复,无需修改子视图)
直接给添加了redacted的父容器叠加半透灰色蒙版,强制覆盖所有子视图的原有底色:
VStack{ TopView() HomeView() } .redacted(.placeholder) // 新增两行代码 .overlay(.gray.opacity(0.4)) // 透明度可根据系统默认占位灰色调整 .allowsHitTesting(false) // 加载状态下禁止交互
- 适用场景:临时快速修复,子视图逻辑复杂不想修改时使用
方案2:子视图条件清空背景(保留系统原生动画)
通过加载状态参数控制,让所有带自定义底色的子视图在加载状态下清空原有背景:
- 先定义加载状态变量
@State var isLoading: Bool = true
- 所有带自定义背景的子视图增加背景条件判断
// 子视图原有示例代码 Text("自定义内容") .background(isLoading ? .clear : Color.customRed) // 加载状态下清空背景
- 父容器控制redacted生效条件
VStack{ TopView(isLoading: isLoading) HomeView(isLoading: isLoading) } .redacted(reason: isLoading ? .placeholder : [])
- 适用场景:需要完全保留系统原生占位闪烁效果,性能最优
方案3:自定义统一Shimmer修饰符(效果完全可控)
如果不需要用系统原生redacted,自定义Shimmer修饰符可以彻底解决底色透出问题,还支持自定义动画参数:
// 自定义Shimmer修饰符 struct ShimmerModifier: ViewModifier { @State private var offset: CGFloat = -1 let isLoading: Bool func body(content: Content) -> some View { if isLoading { content .overlay( GeometryReader { geo in LinearGradient( gradient: Gradient(colors: [.gray.opacity(0.2), .gray.opacity(0.5), .gray.opacity(0.2)]), startPoint: .leading, endPoint: .trailing ) .frame(width: geo.size.width * 2) .offset(x: geo.size.width * offset) .animation(.linear(duration: 1.5).repeatForever(autoreverses: false), value: offset) } ) .mask(content) .onAppear { offset = 1 } } else { content } } } extension View { func shimmer(_ isLoading: Bool) -> some View { self.modifier(ShimmerModifier(isLoading: isLoading)) } }
使用方式:
VStack{ TopView() HomeView() } .shimmer(isLoading)
- 适用场景:需要统一所有视图的加载闪烁效果,或需要定制动画样式时使用
内容的提问来源于stack exchange,提问作者Maharajan S
相关产品推荐
相关产品推荐

