如何让List内容穿透带材质背景的底部栏实现模糊效果 无需知晓底部栏高度
实现方案
优先推荐iOS 15+的原生最优解,使用safeAreaInset修饰符即可完全规避手动计算底部栏高度的问题,效果和系统导航栏的穿透模糊完全一致:
struct ContentView: View { var body: some View { NavigationView { List(1...30, id:\.self) { i in Rectangle() .foregroundColor(Color.random) .frame(height: 36) } .listStyle(PlainListStyle()) // 关键:将底部栏作为底部安全区内嵌视图添加 .safeAreaInset(edge: .bottom) { Text("Bottom bar") .font(.title) .frame(maxWidth: .infinity) .padding() .background(.bar) // 自带毛玻璃模糊效果 } .navigationTitle("Some Nav Title") .navigationBarTitleDisplayMode(.inline) } } } extension Color { static var random: Color { return Color( red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1) ) } }
方案原理
safeAreaInset会自动计算传入的底部视图高度,给List底部添加对应大小的原生内边距,滚动到底部时最后一个列表项刚好完整显示在底部栏上方,无需手动写死高度- List默认撑满全屏,底部栏叠加在List底部区域之上,
.bar材质自带毛玻璃效果,滚动的列表内容会自然穿透底部栏呈现模糊效果,和顶部导航栏表现完全一致 - 无需额外嵌套ZStack,横竖屏切换、动态修改底部栏内容时都能自动适配,不需要额外处理。
如果需要兼容iOS 15以下版本,可以使用GeometryReader动态读取底部栏高度的方案:
struct ContentView: View { @State private var bottomBarHeight: CGFloat = 0 var body: some View { NavigationView { ZStack(alignment: .bottom) { List(1...30, id:\.self) { i in Rectangle() .foregroundColor(Color.random) .frame(height: 36) } .listStyle(PlainListStyle()) .padding(.bottom, bottomBarHeight) // 动态设置底部内边距 Text("Bottom bar") .font(.title) .frame(maxWidth: .infinity) .padding() .background(.bar) // 动态读取自身渲染高度 .background(GeometryReader { proxy in Color.clear.onAppear { bottomBarHeight = proxy.size.height } }) } .navigationTitle("Some Nav Title") .navigationBarTitleDisplayMode(.inline) } } } extension Color { static var random: Color { return Color( red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1) ) } }
该方案同样不需要提前知晓底部栏高度,通过GeometryReader动态获取实际渲染高度赋值给内边距即可适配所有场景。
效果示例:
内容的提问来源于stack exchange,提问作者Steve M
相关产品推荐
相关产品推荐

