UI 更新 Liquid Glass适配
-
sliderBar 样式更新
sliderBar.gif
import SwiftUI
struct LiquidGlassSlider: View {
@Binding var value: Double
var range: ClosedRange<Double> = 0...100
var step: Double = 1
var body: some View {
Slider(value: $value, in: range, step: step)
.accentColor(.blue)
.padding(.horizontal)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white.opacity(0.1))
.backdropEffect(.blur(radius: 10))
.shadow(color: .blue.opacity(0.2), radius: 10, x: 0, y: 5)
)
.padding()
.onChange(of: value) { newValue in
// 添加滑块滑动时的液体效果动画
withAnimation(.easeInOut(duration: 0.2)) {
// 可以在这里添加额外的动画效果
}
}
}
}
// 背景模糊效果扩展
extension View {
func backdropEffect(_ style: UIBlurEffect.Style = .systemUltraThinMaterial) -> some View {
self.background(
UIViewRepresentable { _ in
let view = UIVisualEffectView(effect: UIBlurEffect(style: style))
view.translatesAutoresizingMaskIntoConstraints = false
return view
}
)
}
}
// 使用示例
struct SliderDemo: View {
@State private var sliderValue: Double = 50
var body: some View {
LiquidGlassSlider(value: $sliderValue)
}
}
-
segment 样式更新
segment.gif
import SwiftUI
struct LiquidGlassSegment<T: Hashable>: View {
@Binding var selected: T
var options: [T]
var label: (T) -> String
var body: some View {
HStack(spacing: 2) {
ForEach(options, id: \.self) { option in
Button(action: {
withAnimation(.easeInOut) {
selected = option
}
}) {
Text(label(option))
.font(.subheadline)
.fontWeight(.medium)
.padding(.vertical, 8)
.padding(.horizontal, 16)
.foregroundColor(selected == option ? .white : .primary)
}
.background(
RoundedRectangle(cornerRadius: 8)
.fill(selected == option ? Color.blue : Color.clear)
.transition(.scale.combined(with: .opacity))
)
}
}
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white.opacity(0.1))
.backdropEffect()
.shadow(color: .blue.opacity(0.2), radius: 8, x: 0, y: 2)
)
.padding()
}
}
// 使用示例
struct SegmentDemo: View {
enum Option: String, Hashable, CaseIterable {
case first = "First"
case second = "Second"
case third = "Third"
}
@State private var selectedOption: Option = .first
var body: some View {
LiquidGlassSegment(
selected: $selectedOption,
options: Option.allCases,
label: { $0.rawValue }
)
}
}
-
tabbar更新
image.png
import SwiftUI
struct LiquidGlassTabView: View {
@State private var selectedTab: Int = 0
var body: some View {
TabView(selection: $selectedTab) {
Text("首页")
.tabItem {
Image(systemName: "house")
Text("首页")
}
.tag(0)
Text("搜索")
.tabItem {
Image(systemName: "magnifyingglass")
Text("搜索")
}
.tag(1)
Text("设置")
.tabItem {
Image(systemName: "gear")
Text("设置")
}
.tag(2)
}
.toolbarBackground(
RoundedRectangle(cornerRadius: 15)
.fill(Color.white.opacity(0.1))
.backdropEffect()
.shadow(color: .black.opacity(0.1), radius: 10),
for: .tabBar
)
.toolbarBackground(.visible, for: .tabBar)
.tabBarItemSpacing(10)
.padding(.horizontal, 20)
.padding(.bottom, 10)
.onChange(of: selectedTab) { _ in
// 切换标签时的动画效果
withAnimation(.easeInOut) { }
}
}
}
// 自定义标签栏样式
struct LiquidGlassTabBarStyle: TabBarStyle {
func makeBody(configuration: Configuration) -> some View {
VStack {
Spacer()
HStack {
ForEach(configuration.items.enumerated(), id: \.offset) { index, item in
Button(action: {
configuration.select(index)
}) {
VStack {
item.icon
.font(.system(size: 22))
item.label
.font(.system(size: 10))
}
.padding(.vertical, 8)
.foregroundColor(configuration.selection == index ? .blue : .primary)
.opacity(configuration.selection == index ? 1.0 : 0.7)
}
}
}
.padding(.horizontal, 20)
.frame(height: 50)
.background(
RoundedRectangle(cornerRadius: 15)
.fill(Color.white.opacity(0.1))
.backdropEffect()
.shadow(color: .black.opacity(0.1), radius: 10)
)
.padding(.horizontal, 20)
.padding(.bottom, 10)
}
.ignoresSafeArea(edges: .bottom)
}
}
-
系统工具栏样式更新
image.png
import SwiftUI
struct LiquidGlassToolbar<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ToolbarItem(placement: .bottomBar) {
HStack {
content
}
.padding()
.frame(maxWidth: .infinity)
.background(
RoundedRectangle(cornerRadius: 12)
.fill(Color.white.opacity(0.1))
.backdropEffect()
.shadow(color: .black.opacity(0.1), radius: 8)
)
.padding()
}
}
}
// 使用示例
struct ToolbarDemo: View {
var body: some View {
NavigationStack {
Text("主内容区域")
.navigationTitle("工具栏示例")
.toolbar {
LiquidGlassToolbar {
Button(action: {}) {
Image(systemName: "trash")
.foregroundColor(.red)
}
Spacer()
Button(action: {}) {
Image(systemName: "square.and.arrow.up")
}
Spacer()
Button(action: {}) {
Image(systemName: "heart")
}
Spacer()
Button(action: {}) {
Image(systemName: "ellipsis")
}
}
}
}
}
}
-
系统表格样式更新
image.png
import SwiftUI
struct LiquidGlassTable<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
List {
content
.listRowBackground(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white.opacity(0.05))
.padding(.vertical, 4)
.padding(.horizontal, 8)
)
}
.listStyle(.plain)
.background(Color(.systemBackground).opacity(0.8))
.backdropEffect()
.cornerRadius(15)
.padding()
}
}
// 使用示例
struct TableDemo: View {
let items = ["项目 1", "项目 2", "项目 3", "项目 4", "项目 5"]
var body: some View {
LiquidGlassTable {
ForEach(items, id: \.self) { item in
HStack {
Text(item)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(.secondary)
}
.padding(.vertical, 8)
}
}
}
}
-
搜索栏样式更新
image.png
import SwiftUI
struct LiquidGlassSearchBar: View {
@Binding var text: String
var placeholder: String = "搜索..."
var body: some View {
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.secondary)
TextField(placeholder, text: $text)
.autocapitalization(.none)
if !text.isEmpty {
Button(action: {
text = ""
}) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.secondary)
}
}
}
.padding(.horizontal, 16)
.padding(.vertical, 12)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(Color.white.opacity(0.1))
.backdropEffect()
.shadow(color: .black.opacity(0.1), radius: 5)
)
.padding()
}
}
// 使用示例
struct SearchBarDemo: View {
@State private var searchText: String = ""
var body: some View {
LiquidGlassSearchBar(text: $searchText)
}
}
特性
- SpeechAnalyzer 支持语音转文本
image.png
import Speech
// Step 1: Modules
guard let locale = SpeechTranscriber.supportedLocale(equivalentTo: Locale.current) else {
/* Note unsupported language */
}
let transcriber = SpeechTranscriber(locale: locale, preset: .offlineTranscription)
// Step 2: Assets
if let installationRequest = try await AssetInventory.assetInstallationRequest(supporting: [transcriber]) {
try await installationRequest.downloadAndInstall()
}
// Step 3: Input sequence
let (inputSequence, inputBuilder) = AsyncStream.makeStream(of: AnalyzerInput.self)
// Step 4: Analyzer
let audioFormat = await SpeechAnalyzer.bestAvailableAudioFormat(compatibleWith: [transcriber])
let analyzer = SpeechAnalyzer(modules: [transcriber])
// Step 5: Supply audio
Task {
while /* audio remains */ {
/* Get some audio */
/* Convert to audioFormat */
let pcmBuffer = /* an AVAudioPCMBuffer containing some converted audio */
let input = AnalyzerInput(buffer: pcmBuffer)
inputBuilder.yield(input)
}
inputBuilder.finish()
}
// Step 7: Act on results
Task {
do {
for try await result in transcriber.results {
let bestTranscription = result.text // an AttributedString
let plainTextBestTranscription = String(bestTranscription.characters) // a String
print(plainTextBestTranscription)
}
} catch {
/* Handle error */
}
}
// Step 6: Perform analysis
let lastSampleTime = try await analyzer.analyzeSequence(inputSequence)
// Step 8: Finish analysis
if let lastSampleTime {
try await analyzer.finalizeAndFinish(through: lastSampleTime)
} else {
try analyzer.cancelAndFinishNow()
}






