如何创建适配背景内容的液态玻璃效果工具栏按钮
如何创建适配背景内容的液态玻璃效果工具栏按钮
我完全懂你想要的效果——就是iOS Safari那种双层玻璃质感的工具栏,按钮图标能跟着下方滚动的背景自动切换明暗,而且整个工具栏共享一块平滑的玻璃面板,不会每个按钮都冒出单独的小气泡对吧?我来帮你调整代码,解决这个核心问题。
核心问题拆解
你之前的问题主要出在两个地方:
- 按钮没用到自适应前景样式,导致颜色固定死,不会随背景明暗变化
- 玻璃效果的应用层级不对,要么每个按钮单独生成气泡,要么没让整个工具栏共享同一块玻璃面板
修复后的完整代码
我把你的代码调整后,既保留了两行工具栏的布局,又解决了颜色适配和玻璃气泡的问题:
import SwiftUI @main struct GlassToolbarDemoApp: App { var body: some Scene { WindowGroup { DemoView() } } } struct DemoView: View { @State private var query: String = "" var body: some View { ZStack { // 保留你用来测试的滚动背景 SampleBackgroundScroll() .ignoresSafeArea() // 让背景延伸到安全区外,增强玻璃沉浸感 } // 把工具栏固定在底部(改成.top就能放到顶部) .safeAreaInset(edge: .bottom) { // 整个工具栏的外层玻璃容器——共享同一块玻璃面板 VStack(spacing: 8) { // 第一行:搜索栏 HStack(spacing: 10) { HStack(spacing: 8) { Image(systemName: "magnifyingglass") .foregroundStyle(.secondary) TextField("Search…", text: $query) .textInputAutocapitalization(.never) } .padding(.horizontal, 12) .padding(.vertical, 10) .background( RoundedRectangle(cornerRadius: 14, style: .continuous) .fill(.thinMaterial) // 搜索栏单独的薄玻璃效果 ) } .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, 2) Divider().opacity(0.25) // 第二行:工具栏按钮(核心修改在这里!) HStack(spacing: 20) { // 改成Button还能加点击事件,不影响颜色适配 Button(action: { /* 首页点击逻辑 */ }) { Image(systemName: "house.fill") .font(.system(size:36)) .frame(width: 40, height: 40) } .foregroundStyle(.primary) // 关键:自动随背景切换明暗 Button(action: { /* 搜索点击逻辑 */ }) { Image(systemName: "text.magnifyingglass") .font(.system(size:36)) .frame(width: 40, height: 40) } .foregroundStyle(.primary) Button(action: { /* 新增点击逻辑 */ }) { Image(systemName: "plus.circle.fill") .font(.system(size:36)) .frame(width: 40, height: 40) } .foregroundStyle(.primary) } } .padding(.horizontal, 14) .padding(.vertical, 10) .frame(maxWidth: .infinity) .background(.ultraThinMaterial) // 整个工具栏的玻璃背景,统一面板 .shadow(color: .black.opacity(0.12), radius: 20, y: 10) .padding(.horizontal) .padding(.top, 6) } } } // MARK: - 测试用的滚动背景(保留你的原代码,用来验证适配效果) struct SampleBackgroundScroll: View { var body: some View { ScrollView { LazyVStack(spacing: 0) { demoBlock(.light, title: "Sunny Paper") demoBlock(.dark, title: "Night Slate") demoBlock(.light, title: "Porcelain") demoBlock(.colorful, title: "Aurora Cyan") demoBlock(.dark, title: "Graphite") demoBlock(.colorfulAlt, title: "Sunset Blend") demoBlock(.light, title: "Foggy White") demoBlock(.dark, title: "Charcoal") } } } @ViewBuilder func demoBlock(_ style: BlockStyle, title: String) -> some View { ZStack { switch style { case .light: LinearGradient(colors: [Color.white, Color(white: 0.93)], startPoint: .topLeading, endPoint: .bottomTrailing) case .dark: LinearGradient(colors: [Color.black, Color(white: 0.15)], startPoint: .top, endPoint: .bottom) case .colorful: LinearGradient(colors: [Color.cyan.opacity(0.7), Color.blue.opacity(0.4)], startPoint: .topLeading, endPoint: .bottomTrailing) case .colorfulAlt: LinearGradient(colors: [Color.purple, Color.orange], startPoint: .topLeading, endPoint: .bottomTrailing) } VStack(spacing: 12) { Text(title) .font(.system(size: 28, weight: .bold)) .foregroundStyle(style == .dark ? .white : .primary) Text("Scroll to see how the glass adapts to different backgrounds.") .font(.system(size: 15)) .foregroundStyle(style == .dark ? .white.opacity(0.85) : .secondary) } .padding(.top, 120) } .frame(height: 360) } enum BlockStyle { case light, dark, colorful, colorfulAlt } } #Preview { DemoView() }
关键修改说明
- 统一玻璃容器:把整个两行工具栏放到一个
.background(.ultraThinMaterial)的容器里,这样整个工具栏共享一块玻璃面板,不会出现单独的按钮气泡,完美融合成一个整体。 - 自适应前景色:给每个按钮加
.foregroundStyle(.primary),这是SwiftUI内置的自适应样式——暗背景下自动显示亮色,亮背景下自动显示暗色,完全跟着滚动的内容变化。 - 可选的按钮交互:把Image改成Button,既保留了颜色适配效果,又能添加点击事件,完全符合实际开发需求。
- 简化玻璃逻辑:去掉了之前复杂的
.glassEffectUnion,改用更直接的.background(.ultraThinMaterial),效果更稳定也更容易控制。
现在滚动背景试试,工具栏按钮会自动跟着下方的明暗区域切换颜色,玻璃面板平滑统一,完全就是你想要的Safari同款效果!




