Skip to content

Commit e09c4a3

Browse files
ZhaoChaoqunclaude
andcommitted
Add adaptive width and scroll support for HUD overlay
- HUD width now adapts to text content length - Support up to 5 lines of text display - Auto-scroll to bottom when text exceeds max lines - Change background from Capsule to RoundedRectangle - Increase window size to accommodate more content Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7a1e15b commit e09c4a3

1 file changed

Lines changed: 51 additions & 12 deletions

File tree

Sources/OverlayWindow.swift

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class OverlayWindowController {
1717

1818
// 创建一个无边框的悬浮窗口
1919
window = NSWindow(
20-
contentRect: NSRect(x: 0, y: 0, width: 320, height: 80),
20+
contentRect: NSRect(x: 0, y: 0, width: 400, height: 200),
2121
styleMask: [.borderless],
2222
backing: .buffered,
2323
defer: false
@@ -112,12 +112,17 @@ class OverlayViewModel: ObservableObject {
112112
}
113113
}
114114

115-
/// 悬浮窗口视图 - 类似截图中的样式
115+
/// 悬浮窗口视图 - 自适应宽度与滚动效果
116116
struct OverlayView: View {
117117
@ObservedObject var viewModel: OverlayViewModel
118118

119+
// 布局常量
120+
private let maxWidth: CGFloat = 400 // 最大宽度
121+
private let maxLines: Int = 5 // 最大行数
122+
private let lineHeight: CGFloat = 20 // 每行高度
123+
119124
var body: some View {
120-
VStack(spacing: 8) {
125+
VStack(alignment: .leading, spacing: 8) {
121126
// 主状态指示器
122127
HStack(spacing: 12) {
123128
// 左侧图标区域 - 固定宽度
@@ -146,28 +151,62 @@ struct OverlayView: View {
146151
.foregroundColor(.white)
147152
.frame(width: 75, alignment: .leading)
148153
}
154+
.frame(maxWidth: .infinity, alignment: .center)
149155

150156
// 识别结果显示(当有文字时)
151157
if !viewModel.recognizedText.isEmpty {
152-
Text(viewModel.recognizedText)
153-
.font(.system(size: 13))
154-
.foregroundColor(.white.opacity(0.9))
155-
.lineLimit(2)
156-
.truncationMode(.head)
157-
.frame(maxWidth: 280)
158-
.multilineTextAlignment(.center)
158+
textContentView
159159
}
160160
}
161161
.padding(.horizontal, 16)
162162
.padding(.vertical, 10)
163+
.frame(maxWidth: maxWidth)
163164
.background(
164-
Capsule()
165+
RoundedRectangle(cornerRadius: 16)
165166
.fill(Color.black.opacity(0.75))
166167
)
167-
.animation(.easeInOut(duration: 0.1), value: viewModel.animationPhase)
168+
.animation(.easeInOut(duration: 0.15), value: viewModel.animationPhase)
168169
.animation(.easeInOut(duration: 0.2), value: viewModel.recognizedText)
169170
}
170171

172+
@ViewBuilder
173+
private var textContentView: some View {
174+
let textHeight = calculateTextHeight(viewModel.recognizedText)
175+
let displayHeight = min(textHeight, CGFloat(maxLines) * lineHeight)
176+
let needsScroll = textHeight > displayHeight
177+
178+
if needsScroll {
179+
ScrollViewReader { proxy in
180+
ScrollView(.vertical, showsIndicators: false) {
181+
Text(viewModel.recognizedText)
182+
.font(.system(size: 13))
183+
.foregroundColor(.white.opacity(0.9))
184+
.frame(width: maxWidth - 48, alignment: .leading)
185+
.id("bottom")
186+
}
187+
.frame(width: maxWidth - 32, height: displayHeight)
188+
.onChange(of: viewModel.recognizedText) { _, _ in
189+
withAnimation(.easeOut(duration: 0.15)) {
190+
proxy.scrollTo("bottom", anchor: .bottom)
191+
}
192+
}
193+
}
194+
} else {
195+
Text(viewModel.recognizedText)
196+
.font(.system(size: 13))
197+
.foregroundColor(.white.opacity(0.9))
198+
.frame(maxWidth: maxWidth - 32, alignment: .leading)
199+
.fixedSize(horizontal: false, vertical: true)
200+
}
201+
}
202+
203+
private func calculateTextHeight(_ text: String) -> CGFloat {
204+
// 估算文字行数(简化计算)
205+
let avgCharsPerLine = 25 // 每行大约25个字符
206+
let lines = max(1, (text.count + avgCharsPerLine - 1) / avgCharsPerLine)
207+
return CGFloat(lines) * lineHeight
208+
}
209+
171210
private func waveHeight(for index: Int) -> CGFloat {
172211
let phase = viewModel.animationPhase + CGFloat(index) * 0.6
173212
let baseHeight: CGFloat = 6

0 commit comments

Comments
 (0)