4.将这个效果应用到占位符上
struct Shimmer: ViewModifier { @Stateprivatevar isInitialState = true func body(content: Content) -> some View { content .mask( LinearGradient( gradient: Gradient(colors: [ .black.opacity(0.4), .black, .black.opacity(0.4) ]), startPoint: isInitialState ? UnitPoint(x: -0.3, y: -0.3) : UnitPoint(x: 1, y: 1), endPoint: isInitialState ? UnitPoint(x: 0, y: 0) : UnitPoint(x: 1.3, y: 1.3) ) ) .animation( .linear(duration: 1.5) .delay(0.25) .repeatForever(autoreverses: false), value: isInitialState ) .onAppear { isInitialState = false } } }创建一个简单的加载视图
struct ContentView: View { @Stateprivatevar isLoading = true var body: some View { VStack(spacing: 20) { if isLoading { // 加载状态 VStack(spacing: 15) { Rectangle() .fill(Color.gray.opacity(0.3)) .frame(height: 200) .cornerRadius(10) HStack { Circle() .fill(Color.gray.opacity(0.3)) .frame(width: 60, height: 60) VStack(alignment: .leading, spacing: 8) { Rectangle() .fill(Color.gray.opacity(0.3)) .frame(height: 16) .cornerRadius(8) Rectangle() .fill(Color.gray.opacity(0.3)) .frame(width: 120, height: 16) .cornerRadius(8) } // 堆代码 duidaima.com Spacer() } } .modifier(Shimmer()) } else { // 实际内容 VStack(spacing: 15) { Image("placeholder") .resizable() .aspectRatio(contentMode: .fill) .frame(height: 200) .cornerRadius(10) HStack { Circle() .fill(Color.blue) .frame(width: 60, height: 60) VStack(alignment: .leading, spacing: 8) { Text("美丽的风景") .font(.headline) Text("瑞士 · 阿尔卑斯山") .font(.subheadline) .foregroundColor(.secondary) } Spacer() } } } Button(isLoading ? "加载中..." : "重新加载") { withAnimation { isLoading.toggle() } } .disabled(isLoading) } .padding() .onAppear { // 模拟加载时间 DispatchQueue.main.asyncAfter(deadline: .now() + 3) { withAnimation { isLoading = false } } } } }看看效果(其实是有动画的,只是我截图截断了):
struct ShimmerView: View { @Stateprivatevar startPoint = UnitPoint(x: -1.8, y: -1.2) @Stateprivatevar endPoint = UnitPoint(x: 0, y: -0.2) privatelet gradientColors = [ Color.gray.opacity(0.2), Color.white.opacity(0.2), Color.gray.opacity(0.2) ] var body: some View { LinearGradient( colors: gradientColors, startPoint: startPoint, endPoint: endPoint ) .onAppear { withAnimation( .easeInOut(duration: 1) .repeatForever(autoreverses: false) ) { startPoint = UnitPoint(x: 1, y: 1) endPoint = UnitPoint(x: 2.2, y: 2.2) } } } }实际应用场景
4.分页加载 - 在加载更多内容时显示
4.无障碍支持 - 记得为使用辅助功能的用户提供替代方案