You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
4.0 KiB
110 lines
4.0 KiB
import SwiftUI
|
|
|
|
// MARK: - 通用文本输入组件
|
|
struct TextInputView: View {
|
|
@Binding var content: String
|
|
@FocusState var isContentFieldFocused: Bool
|
|
let placeholder: String
|
|
let maxCharacters: Int
|
|
|
|
var body: some View {
|
|
VStack(spacing: 8) {
|
|
ZStack {
|
|
// 输入框主体
|
|
TextEditor(text: $content)
|
|
.frame(minHeight: 120)
|
|
.padding(8)
|
|
.background(Color(.systemBackground))
|
|
.cornerRadius(8)
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 8)
|
|
.stroke(isContentFieldFocused ? Color.blue : Color(.systemGray4), lineWidth: 1)
|
|
)
|
|
.focused($isContentFieldFocused)
|
|
.onChange(of: content) { newValue in
|
|
// 限制最大字符数
|
|
if newValue.count > maxCharacters {
|
|
content = String(newValue.prefix(maxCharacters))
|
|
}
|
|
}
|
|
.toolbar {
|
|
ToolbarItemGroup(placement: .keyboard) {
|
|
Spacer()
|
|
Button("完成") {
|
|
isContentFieldFocused = false
|
|
}
|
|
.foregroundColor(.blue)
|
|
.font(.system(size: 16, weight: .medium))
|
|
}
|
|
}
|
|
|
|
// 占位符文本 - 左上角对齐
|
|
if content.isEmpty && !isContentFieldFocused {
|
|
VStack {
|
|
HStack {
|
|
Text(placeholder)
|
|
.foregroundColor(.secondary)
|
|
.font(.body)
|
|
Spacer()
|
|
}
|
|
Spacer()
|
|
}
|
|
.padding(16)
|
|
.allowsHitTesting(false)
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
|
}
|
|
}
|
|
|
|
// 字符计数和限制提示 - 输入框底下
|
|
HStack {
|
|
Spacer() // Pushes content to the right
|
|
|
|
VStack(alignment: .trailing, spacing: 4) {
|
|
// 字符限制提示
|
|
if content.count >= maxCharacters {
|
|
HStack(spacing: 4) {
|
|
Image(systemName: "exclamationmark.triangle")
|
|
.font(.caption)
|
|
.foregroundColor(.orange)
|
|
Text("已达到最大字符数")
|
|
.font(.caption)
|
|
.foregroundColor(.orange)
|
|
}
|
|
} else if content.count >= Int(Double(maxCharacters) * 0.93) {
|
|
HStack(spacing: 4) {
|
|
Image(systemName: "info.circle")
|
|
.font(.caption)
|
|
.foregroundColor(.blue)
|
|
Text("接近字符限制")
|
|
.font(.caption)
|
|
.foregroundColor(.blue)
|
|
}
|
|
}
|
|
|
|
// 字符计数
|
|
Text("\(content.count)/\(maxCharacters)")
|
|
.font(.caption)
|
|
.foregroundColor(getCharacterCountColor())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func getCharacterCountColor() -> Color {
|
|
if content.count >= maxCharacters {
|
|
return .orange
|
|
} else if content.count >= Int(Double(maxCharacters) * 0.93) {
|
|
return .blue
|
|
} else {
|
|
return .secondary
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
TextInputView(
|
|
content: .constant(""),
|
|
placeholder: "输入任意文本内容...",
|
|
maxCharacters: 150
|
|
)
|
|
} |