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

SwiftUI中如何实现跨App粘贴文本到OTP输入框及decimalPad键盘Done按钮缺失问题

问题1:OTP输入框无法触发粘贴弹窗

原因

你代码中在isEditing == true时将TextField的宽度设为了0,此时TextField的可交互响应区域完全消失,系统无法识别到双击/长按手势,自然无法弹出粘贴菜单。

解决方案

  • 移除TextField的动态width修改逻辑,不要将编辑状态下的宽度设为0,改为保持TextField的尺寸和上层OTP展示框的整体尺寸一致,仅将TextField的文字透明度设为0即可,保留完整的交互响应区域。修改后的TextField代码参考:
TextField("", text: $viewModel.otpField) { isEditing in
    viewModel.isEditing = isEditing
}
.font(Font.system(size: 50, design: .default))
.offset(y: 10)
// 移除原宽度判断,固定为整体OTP框的宽度
.frame(width: textFieldOriginalWidth, height: textBoxHeight)
.textContentType(.oneTimeCode)
// 仅将文字设为透明,保留交互
.foregroundColor(.clear)
.background(Color.clear)
.keyboardType(.decimalPad)
  • 可选兼容方案:给上层展示OTP数字的HStack添加长按手势,手动触发粘贴操作:
HStack (spacing: spaceBetweenLines) {
    // 原ForEach内容保持不变
}
.onLongPressGesture {
    guard let pasteString = UIPasteboard.general.string else { return }
    // 过滤非数字字符,仅保留和验证码位数匹配的长度
    let filtered = pasteString.filter { $0.isNumber }.prefix(viewModel.numberOfFields)
    viewModel.otpField = String(filtered)
}
问题2:decimalPad数字键盘无Done按钮

原因

系统原生的decimalPad数字键盘默认就不携带Done按钮,这是iOS的系统默认行为,和你的代码逻辑无关。

解决方案

你需要手动给TextField添加键盘顶部的附加视图(inputAccessoryView),Xcode 12.3 对应的SwiftUI版本没有原生的inputAccessoryView modifier,你可以通过UIViewRepresentable封装UITextField来实现,参考实现如下:
首先添加带Toolbar的TextField封装:

@available(iOS 13.0, *)
struct ToolbarTextField: UIViewRepresentable {
    @Binding var text: String
    let keyboardType: UIKeyboardType
    let contentType: UITextContentType?
    let onEditingChanged: (Bool) -> Void
    
    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.keyboardType = keyboardType
        if let contentType = contentType {
            textField.textContentType = contentType
        }
        textField.delegate = context.coordinator
        textField.addTarget(context.coordinator, action: #selector(Coordinator.textDidChange), for: .editingChanged)
        
        // 添加顶部Toolbar
        let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44))
        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let doneBtn = UIBarButtonItem(barButtonSystemItem: .done, target: context.coordinator, action: #selector(Coordinator.dismissKeyboard))
        toolbar.items = [flexSpace, doneBtn]
        toolbar.sizeToFit()
        textField.inputAccessoryView = toolbar
        
        return textField
    }
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(text: $text, onEditingChanged: onEditingChanged)
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
        @Binding var text: String
        let onEditingChanged: (Bool) -> Void
        
        init(text: Binding<String>, onEditingChanged: @escaping (Bool) -> Void) {
            self._text = text
            self.onEditingChanged = onEditingChanged
        }
        
        @objc func textDidChange(_ textField: UITextField) {
            text = textField.text ?? ""
        }
        
        @objc func dismissKeyboard() {
            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        }
        
        func textFieldDidBeginEditing(_ textField: UITextField) {
            onEditingChanged(true)
        }
        
        func textFieldDidEndEditing(_ textField: UITextField) {
            onEditingChanged(false)
        }
    }
}

替换你原来的SwiftUI TextField为这个封装好的ToolbarTextField即可正常显示Done按钮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 16:09:03