diff --git a/Note/FormatterView.swift b/Note/FormatterView.swift index f66eb08..d930c40 100644 --- a/Note/FormatterView.swift +++ b/Note/FormatterView.swift @@ -15,14 +15,19 @@ struct FormatterView: View { var body: some View { NavigationStack { VStack(spacing: 0) { - headerView - inputArea .frame(maxHeight: .infinity) actionArea } .background(Color(.systemGroupedBackground).ignoresSafeArea()) + .navigationTitle("文案格式化") + .navigationBarTitleDisplayMode(.large) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + MoreMenuBarButton(text: $inputText, showCopied: $showCopied) + } + } .alert("提示", isPresented: $showEmptyAlert) { Button("确定", role: .cancel) {} } message: { @@ -44,42 +49,6 @@ struct FormatterView: View { .transition(.opacity) } } - .navigationBarHidden(true) - } - } - - private var headerView: some View { - HStack { - Text("文案格式化") - .font(.largeTitle.bold()) - .foregroundStyle(.primary) - Spacer() - Menu { - Button(action: copyText) { - Label("复制", systemImage: "doc.on.doc") - } - .disabled(inputText.isEmpty) - Button(role: .destructive, action: clearText) { - Label("清除", systemImage: "xmark.circle") - } - .disabled(inputText.isEmpty) - } label: { - Image(systemName: "ellipsis") - .font(.system(size: 20, weight: .bold)) - .foregroundStyle(.primary) - .frame(width: 44, height: 44) - .background(.ultraThinMaterial) - .clipShape(Circle()) - } - } - .frame(maxWidth: .infinity, minHeight: 44) - .padding(.horizontal) - .padding(.top, 8) - .padding(.bottom, 8) - .background(Color(.systemGroupedBackground)) - .contentShape(Rectangle()) - .onTapGesture { - dismissKeyboard() } } @@ -175,21 +144,6 @@ struct FormatterView: View { dismissKeyboard() } - private func copyText() { - UIPasteboard.general.string = inputText - withAnimation { - showCopied = true - } - DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { - withAnimation { - showCopied = false - } - } - } - - private func clearText() { - inputText = "" - } } #Preview { diff --git a/Note/MoreMenuBarButton.swift b/Note/MoreMenuBarButton.swift new file mode 100644 index 0000000..4caaa25 --- /dev/null +++ b/Note/MoreMenuBarButton.swift @@ -0,0 +1,87 @@ +// +// MoreMenuBarButton.swift +// Note +// +// Created by fish on 2026/7/12. +// + +import SwiftUI + +struct MoreMenuBarButton: UIViewRepresentable { + @Binding var text: String + @Binding var showCopied: Bool + + func makeUIView(context: Context) -> UIView { + let button = makeGlassButton() + button.menu = context.coordinator.makeMenu() + button.showsMenuAsPrimaryAction = true + + let barButtonItem = UIBarButtonItem(customView: button) + context.coordinator.barButtonItem = barButtonItem + context.coordinator.button = button + + return button + } + + func updateUIView(_ uiView: UIView, context: Context) { + context.coordinator.button?.menu = context.coordinator.makeMenu() + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + private func makeGlassButton() -> UIButton { + let button = UIButton(type: .system) + button.setImage(UIImage(systemName: "ellipsis"), for: .normal) + button.tintColor = UIColor.label + button.frame = CGRect(x: 0, y: 0, width: 44, height: 44) + button.layer.cornerRadius = 22 + button.clipsToBounds = true + + let blurEffect = UIBlurEffect(style: .systemUltraThinMaterial) + let blurView = UIVisualEffectView(effect: blurEffect) + blurView.frame = button.bounds + blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + blurView.isUserInteractionEnabled = false + button.insertSubview(blurView, at: 0) + + return button + } + + class Coordinator { + var parent: MoreMenuBarButton + weak var barButtonItem: UIBarButtonItem? + weak var button: UIButton? + + init(_ parent: MoreMenuBarButton) { + self.parent = parent + } + + func makeMenu() -> UIMenu { + let copyAction = UIAction( + title: "复制", + image: UIImage(systemName: "doc.on.doc"), + attributes: parent.text.isEmpty ? .disabled : [], + handler: { [weak self] _ in + UIPasteboard.general.string = self?.parent.text ?? "" + self?.parent.showCopied = true + DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { + self?.parent.showCopied = false + } + } + ) + + let clearAction = UIAction( + title: "清除", + image: UIImage(systemName: "xmark.circle"), + attributes: parent.text.isEmpty ? [.disabled, .destructive] : .destructive, + handler: { [weak self] _ in + self?.parent.text = "" + } + ) + + return UIMenu(title: "", children: [copyAction, clearAction]) + } + } +}