Как создать кнопку панели инструментов жидкого стекла, которая адаптируется к фоновому содержаниюIOS

Программируем под IOS
Ответить
Anonymous
 Как создать кнопку панели инструментов жидкого стекла, которая адаптируется к фоновому содержанию

Сообщение Anonymous »

У меня есть следующий код, пытающийся создать панель инструментов с двумя строками, как я видел из ios safari 26, но проблема в том, что структура инструментов на самом деле не адаптируется к цвету фона, она остается темной, когда на темном фоне. Я также пытался использовать .buttonstyle (.glass) , который также создает капсульный пузырь вокруг каждой кнопки. Будьте адаптивны к фоновому содержанию Scrollview.

Код: Выделить всё

// MARK: - Toolbar Button, but not adaptive to background content color
struct ToolbarButton: View {
var icon: String
var label: String
var isSelected: Bool
var action: () -> Void

var body: some View {
Image(systemName: icon)
.font(.system(size: 18, weight: .semibold))
.symbolVariant(isSelected ? .fill : .none)
.frame(maxWidth: .infinity)
.padding(.vertical, 6)
.contentShape(Rectangle())
.onTapGesture {
action()
}
}
}
< /code>
import SwiftUI

@main
struct GlassToolbarDemoApp: App {
var body: some Scene {
WindowGroup {
DemoView()
}
}
}

struct DemoView: View {
@State private var selectedTab: Tab = .home
@State private var query: String = ""
@Environment(\.horizontalSizeClass) private var hSizeClass

var body: some View {
ZStack {
SampleBackgroundScroll()
.ignoresSafeArea() // let content run under the glass for a better effect
}
// Pin our two-row glass toolbar to the TOP.  Change to .bottom to make it a bottom toolbar.
.safeAreaInset(edge: .bottom) {
GlassBar {
// ACCESSORY ROW (above the buttons)
HStack(spacing: 10) {
// Search field
HStack(spacing: 8) {
Image(systemName: "magnifyingglass")
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)
} mainRow: {
// MAIN TOOLBAR BUTTONS ROW
if hSizeClass == .compact {
HStack(spacing: 0) {
ToolbarButton(icon: "house.fill", label: "Home", isSelected: selectedTab == .home) { selectedTab = .home }
ToolbarButton(icon: "text.magnifyingglass", label: "Discover", isSelected: selectedTab == .discover) { selectedTab = .discover }
ToolbarButton(icon: "plus.circle.fill", label: "Add", isSelected: selectedTab == .add) { selectedTab = .add }
ToolbarButton(icon: "star.fill", label: "Saved", isSelected: selectedTab == .saved) { selectedTab = .saved }
ToolbarButton(icon: "person.fill", label: "Me", isSelected: selectedTab == .me) { selectedTab = .me }
}
} else {
// On iPad / regular width, show accessory and buttons in ONE row (no height waste)
HStack(spacing: 16) {
ToolbarButton(icon: "house.fill", label: "Home", isSelected: selectedTab == .home) { selectedTab = .home }
ToolbarButton(icon: "text.magnifyingglass", label: "Discover", isSelected: selectedTab == .discover) { selectedTab = .discover }
ToolbarButton(icon: "plus.circle.fill", label: "Add", isSelected: selectedTab == .add) { selectedTab = .add }
ToolbarButton(icon: "star.fill", label: "Saved", isSelected: selectedTab == .saved) { selectedTab = .saved }
ToolbarButton(icon: "person.fill", label: "Me", isSelected: selectedTab == .me) { selectedTab = .me }

Spacer(minLength: 16)

HStack(spacing: 10) {
HStack(spacing: 8) {
Image(systemName: "magnifyingglass")
TextField("Search…", text: $query)
.textInputAutocapitalization(.never)
}
.padding(.horizontal, 12)
.padding(.vertical, 10)
.background(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(.thinMaterial)
)
}
.frame(maxWidth: 420)
}
}
}
}
}
}

// MARK: - Glass Bar (two-row toolbar)
struct GlassBar: View {
var accessoryRow: Accessory
var mainRow: Main

init(@ViewBuilder accessory: () -> Accessory, @ViewBuilder mainRow: () ->  Main) {
self.accessoryRow = accessory()
self.mainRow = mainRow()
}

var body: some View {
VStack(spacing: 8) {
accessoryRow
Divider().opacity(0.25)
mainRow
}
.padding(.horizontal, 14)
.padding(.vertical, 10)
.frame(maxWidth: .infinity)
.background(GlassBackground(cornerRadius: 26))
.padding(.horizontal)
.padding(.top, 6)
.shadow(color: .black.opacity(0.12), radius: 20, y: 10)
}
}

// MARK: - Glass Background helper
struct GlassBackground: View {
var cornerRadius: CGFloat = 10

var body: some View {
Group {
if #available(iOS 26.0, *) {
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.fill(.clear)
.glassEffect(.clear)
} else {
// Fallback for older OSes: use material to approximate the effect.
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.fill(.ultraThinMaterial)
.overlay(
// subtle highlight to simulate glass rim
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.strokeBorder(.white.opacity(0.08), lineWidth: 1)
)
}
}
}
}

// MARK: - Toolbar Button
struct ToolbarButton: View {
var icon: String
var label: String
var isSelected: Bool
var action: () -> Void

var body: some View {
Image(systemName: icon)
.font(.system(size: 18, weight: .semibold))
.symbolVariant(isSelected ? .fill : .none)

.frame(maxWidth: .infinity)
.padding(.vertical, 6)
.contentShape(Rectangle())
.onTapGesture {
action()
}
}
}

// MARK: - Demo background content to show light/dark behind glass
struct SampleBackgroundScroll: View {
var body: some View {
ScrollView {
LazyVStack(spacing: 0) {
demoBlock(.light, title: "Sunny Paper")
demoBlock(.dark, title: "Night Slate")
demoBlock(.colorful, title: "Aurora Cyan")
demoBlock(.light, title: "Porcelain")
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 }
}

// MARK: - Tabs
enum Tab { case home, discover, add, saved, me }

#Preview {
DemoView()
}




Подробнее здесь: https://stackoverflow.com/questions/797 ... nd-content
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»