You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何为垂直方向的TextField使用.onSubmit()方法?

解决SwiftUI垂直扩展TextField软键盘发送按钮不触发onSubmit的问题

在iOS 16+中使用TextField(_:text:axis:)创建可垂直扩展的多行文本框,设置.submitLabel(.send)后,软键盘的蓝色“发送”按钮仅会插入换行符,无法触发.onSubmit回调;但硬件键盘按下回车键却能正常触发。这是因为垂直模式下的TextField底层对应UITextView,其默认行为是将return键作为换行输入。

解决方案:自定义多行文本框封装

通过封装UITextView实现自定义提交逻辑,同时保留垂直扩展和原生输入体验:

import SwiftUI

struct MultilineTextField: UIViewRepresentable {
    @Binding var text: String
    var placeholder: String
    var onSubmit: () -> Void
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.font = UIFont.systemFont(ofSize: 16)
        textView.textColor = .label
        textView.returnKeyType = .send
        textView.delegate = context.coordinator
        textView.text = placeholder
        textView.textColor = .placeholderText
        textView.backgroundColor = .clear // 适配SwiftUI背景样式
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        if uiView.text != text && !(text.isEmpty && uiView.text == placeholder) {
            uiView.text = text.isEmpty ? placeholder : text
            uiView.textColor = text.isEmpty ? .placeholderText : .label
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        let parent: MultilineTextField
        
        init(parent: MultilineTextField) {
            self.parent = parent
        }
        
        func textViewDidBeginEditing(_ textView: UITextView) {
            if textView.text == parent.placeholder {
                textView.text = ""
                textView.textColor = .label
            }
        }
        
        func textViewDidEndEditing(_ textView: UITextView) {
            parent.text = textView.text.trimmingCharacters(in: .whitespacesAndNewlines)
            if parent.text.isEmpty {
                textView.text = parent.placeholder
                textView.textColor = .placeholderText
            }
        }
        
        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            // 拦截发送按钮点击事件,触发提交逻辑
            if text == "\n" {
                parent.onSubmit()
                textView.resignFirstResponder() // 可选:提交后自动收起键盘
                return false
            }
            return true
        }
    }
}

// 使用示例
struct ContentView: View {
    @State var message: String = ""
    
    var body: some View {
        VStack(spacing: 16) {
            Text("点击软键盘的发送按钮提交内容")
                .font(.subheadline)
                .foregroundColor(.secondary)
            
            MultilineTextField(text: $message, placeholder: "输入消息...", onSubmit: {
                guard !message.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return }
                print("提交成功!内容:\(message)")
                message = "" // 提交后清空输入框
            })
            .frame(minHeight: 80, maxHeight: .infinity)
            .padding(.horizontal, 12)
            .padding(.vertical, 8)
            .border(Color.gray.opacity(0.3), cornerRadius: 8)
        }
        .padding()
    }
}

说明

  • 自定义文本框保留了原生垂直扩展特性,同时将软键盘“发送”按钮绑定到提交回调
  • 硬件键盘可通过Shift + Enter实现换行,若需调整换行逻辑,可修改shouldChangeTextIn方法的判断条件
  • 内置占位符处理逻辑,与原生TextField体验一致

内容的提问来源于stack exchange,提问作者Android KitKat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 12:40:21