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

SwiftUI中如何通过Binding布尔值控制自定义UITextView的焦点状态

问题解答

现有代码无法实现你期望的功能——因为当前代码没有监听isFirstResponder的状态变化,也没有触发UITextView获取/失去焦点的逻辑。要实现需求,需要对代码做以下两处修改:


修改点1:在updateUIView中处理焦点切换

在updateUIView方法里添加对isFirstResponder绑定值的判断,根据状态触发UITextView的焦点操作:

func updateUIView(_ uiView: UITextView, context: Context){
    DispatchQueue.main.async{
        // 处理焦点状态
        if self.isFirstResponder != uiView.isFirstResponder {
            if self.isFirstResponder {
                uiView.becomeFirstResponder()
            } else {
                uiView.resignFirstResponder()
            }
        }
        
        // 原有高度计算逻辑
        if uiView.contentSize.height < maxHeight {
            self.height = uiView.contentSize.height
            self.lines = uiView.contentSize.height == 38 ? 0 : (uiView.contentSize.height / 21 * 13 - 38)
        }
        uiView.text = self.txt
    }
}

修改点2:在Coordinator中同步焦点状态到绑定值

在Coordinator类中补充两个UITextViewDelegate方法,确保用户手动操作(点击文本框/收起键盘)时,isFirstResponder绑定值能同步更新:

class Coordinator: NSObject, UITextViewDelegate{
    
    var parent: ResizableTF
    let maxHeight: CGFloat = 150
    init(parent1: ResizableTF) {
        parent = parent1
    }
    
    func textViewDidBeginEditing(_ textView: UITextView) {
        parent.isFirstResponder = true // 同步开始编辑状态
        if self.parent.txt == "" {
            textView.text = ""
            textView.textColor = .black
        }
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        parent.isFirstResponder = false // 同步结束编辑状态
    }
    
    func textViewDidChange(_ textView: UITextView) {
        DispatchQueue.main.async {
            if textView.contentSize.height < self.maxHeight {
                self.parent.height = textView.contentSize.height
            }
            self.parent.txt = textView.text
        }
    }
}

修改后的完整代码

import Foundation
import SwiftUI

struct ResizableTF: UIViewRepresentable {
    
    @Binding var txt: String
    @Binding var height: CGFloat
    @Binding var lines: CGFloat
    @Binding var isFirstResponder: Bool
    
    let maxHeight: CGFloat = 150
    
    func makeCoordinator() -> Coordinator {
        return ResizableTF.Coordinator(parent1: self)
    }
    
    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.isEditable = true
        view.isUserInteractionEnabled = true
        view.isScrollEnabled = true
        view.font = .systemFont(ofSize: 18)
        view.textColor = .gray
        view.backgroundColor = .clear
        view.delegate = context.coordinator
        return view
    }
    
    func updateUIView(_ uiView: UITextView, context: Context){
        DispatchQueue.main.async{
            // 处理焦点状态同步
            if self.isFirstResponder != uiView.isFirstResponder {
                self.isFirstResponder ? uiView.becomeFirstResponder() : uiView.resignFirstResponder()
            }
            
            // 原有高度与文本同步逻辑
            if uiView.contentSize.height < maxHeight {
                self.height = uiView.contentSize.height
                self.lines = uiView.contentSize.height == 38 ? 0 : (uiView.contentSize.height / 21 * 13 - 38)
            }
            uiView.text = self.txt
        }
    }
    
    class Coordinator: NSObject, UITextViewDelegate{
        
        var parent: ResizableTF
        let maxHeight: CGFloat = 150
        
        init(parent1: ResizableTF) {
            parent = parent1
        }
        
        func textViewDidBeginEditing(_ textView: UITextView) {
            parent.isFirstResponder = true
            if parent.txt.isEmpty {
                textView.text = ""
                textView.textColor = .black
            }
        }
        
        func textViewDidEndEditing(_ textView: UITextView) {
            parent.isFirstResponder = false
        }
        
        func textViewDidChange(_ textView: UITextView) {
            DispatchQueue.main.async {
                if textView.contentSize.height < self.maxHeight {
                    self.parent.height = textView.contentSize.height
                }
                self.parent.txt = textView.text
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:35:31