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.

273 lines
8.2 KiB

import SwiftUI
// MARK: -
struct KeyboardToolbarView: View {
let onDone: () -> Void
let showDoneButton: Bool
let additionalButtons: [KeyboardToolbarButton]
init(
onDone: @escaping () -> Void = {},
showDoneButton: Bool = true,
additionalButtons: [KeyboardToolbarButton] = []
) {
self.onDone = onDone
self.showDoneButton = showDoneButton
self.additionalButtons = additionalButtons
}
var body: some View {
Group {
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .left }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
}
Spacer()
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .right }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
if showDoneButton {
Button("完成", action: onDone)
.foregroundColor(.blue)
.font(.system(size: 16, weight: .medium))
}
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .left }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
}
Spacer()
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .right }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
if showDoneButton {
Button("完成", action: onDone)
.foregroundColor(.blue)
.font(.system(size: 16, weight: .medium))
}
}
}
}
}
}
// MARK: -
struct KeyboardToolbarButton {
let id = UUID()
let title: String
let icon: String?
let color: Color
let position: ButtonPosition
let action: () -> Void
enum ButtonPosition {
case left, right
}
init(
title: String,
icon: String? = nil,
color: Color = .blue,
position: ButtonPosition = .right,
action: @escaping () -> Void
) {
self.title = title
self.icon = icon
self.color = color
self.position = position
self.action = action
}
}
// MARK: -
extension KeyboardToolbarButton {
static func clear(
text: Binding<String>,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: "清空",
icon: "trash",
color: .red,
position: position
) {
text.wrappedValue = ""
}
}
static func copy(
text: String,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: "复制",
icon: "doc.on.doc",
color: .blue,
position: position
) {
UIPasteboard.general.string = text
}
}
static func paste(
text: Binding<String>,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: "粘贴",
icon: "doc.on.clipboard",
color: .green,
position: position
) {
if let pastedText = UIPasteboard.general.string {
text.wrappedValue = pastedText
}
}
}
static func next(
action: @escaping () -> Void,
position: ButtonPosition = .right
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: "下一个",
icon: "arrow.right",
color: .blue,
position: position,
action: action
)
}
static func previous(
action: @escaping () -> Void,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: "上一个",
icon: "arrow.left",
color: .blue,
position: position,
action: action
)
}
}
// MARK: -
extension KeyboardToolbarView {
static func simple(onDone: @escaping () -> Void = {}) -> KeyboardToolbarView {
KeyboardToolbarView(onDone: onDone)
}
static func withClear(
text: Binding<String>,
onDone: @escaping () -> Void = {}
) -> KeyboardToolbarView {
KeyboardToolbarView(
onDone: onDone,
additionalButtons: [
.clear(text: text)
]
)
}
static func withCopyPaste(
text: Binding<String>,
onDone: @escaping () -> Void = {}
) -> KeyboardToolbarView {
KeyboardToolbarView(
onDone: onDone,
additionalButtons: [
.copy(text: text.wrappedValue),
.paste(text: text)
]
)
}
static func withNavigation(
onPrevious: @escaping () -> Void,
onNext: @escaping () -> Void,
onDone: @escaping () -> Void = {}
) -> KeyboardToolbarView {
KeyboardToolbarView(
onDone: onDone,
additionalButtons: [
.previous(action: onPrevious),
.next(action: onNext)
]
)
}
}
#Preview {
VStack(spacing: 16) {
Text("简单工具栏")
.font(.headline)
Text("带清空按钮的工具栏")
.font(.headline)
Text("带复制粘贴的工具栏")
.font(.headline)
Text("带导航的工具栏")
.font(.headline)
}
.padding()
}