SwiftUI技巧:滚动手势下实现ZStack覆盖上方视图
需求实现:滚动时让ZStack覆盖顶部视图
我有一个包含两部分的界面:
- 第一部分:"For You"标题、用户头像,搭配搜索栏
- 第二部分:嵌套ForEach的ZStack,展示多个重叠的彩色矩形
期望效果:向上滚动矩形区域时,ZStack能向上移动并覆盖第一部分视图。
修改后的完整可运行代码
import SwiftUI // 补充代码中缺失的Tag结构体 struct Tag: Identifiable { let id: UUID let name: String let color: String } // 补充HEX颜色转换扩展 extension Color { init(hex: String) { let cleanHex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var hexValue: UInt64 = 0 Scanner(string: cleanHex).scanHexInt64(&hexValue) let a, r, g, b: UInt64 switch cleanHex.count { case 3: (a, r, g, b) = (255, (hexValue >> 8) * 17, (hexValue >> 4 & 0xF) * 17, (hexValue & 0xF) * 17) case 6: (a, r, g, b) = (255, hexValue >> 16, hexValue >> 8 & 0xFF, hexValue & 0xFF) case 8: (a, r, g, b) = (hexValue >> 24, hexValue >> 16 & 0xFF, hexValue >> 8 & 0xFF, hexValue & 0xFF) default: (a, r, g, b) = (1, 1, 1, 0) } self.init( .sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: Double(a) / 255 ) } } struct Playground4: View { var controlPoint = 0.0 @State private var bookTags = [ Tag(id: UUID(), name: "Adventure", color: "6d7aef"), Tag(id: UUID(), name: "Drama", color: "c096f2"), Tag(id: UUID(), name: "Romance", color: "d681b0"), Tag(id: UUID(), name: "Discover", color: "8ad5e0"), Tag(id: UUID(), name: "Design", color: "db6446"), Tag(id: UUID(), name: "Action", color: "e8d272"), Tag(id: UUID(), name: "History", color: "8fb1e1"), Tag(id: UUID(), name: "Recommended", color: "325eb5"), ] var body: some View { ZStack(alignment: .top) { // 滚动的矩形区域(第二部分) ScrollView { ZStack(alignment: .top) { ForEach(Array(bookTags.enumerated()), id: \.element.id) { index, tag in Rectangle() .frame(height: 300) .foregroundColor(Color(hex: tag.color)) .shadow(color: .black.opacity(0.1), radius: 5, x: 5, y: 5) .shadow(color: .black.opacity(0.1), radius: 5, x: -5, y: -5) .overlay(alignment: .topLeading) { Text(tag.name) .font(.system(size: 30, weight: .bold, design: .rounded)) .foregroundColor(.white) .padding(.horizontal, 30) .padding(.top, 30) } .padding(.top, index != 0 ? CGFloat(index) * 75 : 0) } } .padding(.top, 160) // 预留顶部视图高度,初始不遮挡 .edgesIgnoringSafeArea(.bottom) } // 顶部固定视图(第一部分) VStack(alignment: .leading, spacing: 0) { HStack { Text("For You") .font(.system(size: 28, weight: .black, design: .rounded)) Spacer() Image(systemName: "person.circle.fill") .foregroundColor(.gray) .font(.system(size: 30)) } .padding(30) HStack { Image(systemName: "magnifyingglass") Text("Book or author") .opacity(0.8) .font(.system(size: 16, weight: .heavy, design: .rounded)) .kerning(1) .foregroundColor(.gray) .padding(.leading, 10) } .padding(30) .background(Color.white) // 初始状态遮挡下方内容 } } } } struct Playground4_Previews: PreviewProvider { static var previews: some View { Playground4() } }
核心改动说明
- 整体结构改为ZStack包裹顶部视图和ScrollView,让滚动内容可以在顶部视图下方滚动并覆盖它
- 给ScrollView内的ZStack添加顶部内边距,预留出顶部视图的高度,保证初始状态下矩形不会遮挡顶部内容
- 顶部搜索栏添加白色背景,确保初始状态下能完全遮挡下方的矩形区域
- 优化Overlay布局,简化代码结构
内容的提问来源于stack exchange,提问作者N G
相关产品推荐
相关产品推荐

