Swiftui - 从 UIViewRepresentable 访问 UIKit 方法/属性

Posted

技术标签:

【中文标题】Swiftui - 从 UIViewRepresentable 访问 UIKit 方法/属性【英文标题】:Swiftui - Access UIKit methods/properties from UIViewRepresentable 【发布时间】:2020-12-07 11:51:48 【问题描述】:

我使用 UIViewRepresentable(下面的代码)创建了一个基于 UITextView 的 SwiftUI TextView。在 Swiftui 中显示文本工作正常。

但现在我需要从我的模型中访问 UITextView 的内部函数。我怎么称呼例如UITextView.scrollRangeToVisible(_:) 或访问 UITextView.isEditable 之类的属性?

我的模型需要根据内部模型状态进行这些修改。

有什么想法吗?谢谢

(p.s. 我知道 SwiftUI 中的 TextEditor,但我需要对 ios 13 的支持!)

struct TextView: UIViewRepresentable 
  @ObservedObject var config: ConfigModel = .shared
  @Binding var text: String
  
  @State var isEditable: Bool
  var borderColor: UIColor
  var borderWidth: CGFloat
  
  func makeCoordinator() -> Coordinator 
    Coordinator(self)
  
  
  func makeUIView(context: Context) -> UITextView 
    let myTextView = UITextView()
    myTextView.delegate = context.coordinator
    
    myTextView.isScrollEnabled = true
    myTextView.isEditable = isEditable
    myTextView.isUserInteractionEnabled = true
    myTextView.layer.borderColor = borderColor.cgColor
    myTextView.layer.borderWidth = borderWidth
    myTextView.layer.cornerRadius = 8
    return myTextView
  
  
  func updateUIView(_ uiView: UITextView, context: Context) 
    uiView.font = uiView.font?.withSize(CGFloat(config.textsize))
    uiView.text = text
  
  
  class Coordinator : NSObject, UITextViewDelegate 
    
    var parent: TextView
    
    init(_ uiTextView: TextView) 
      self.parent = uiTextView
    
    
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool 
      return true
    
    
    func textViewDidChange(_ textView: UITextView) 
      self.parent.text = textView.text
    
  

【问题讨论】:

我知道这篇文章,但我的问题如何在运行时访问 UIKit 函数并没有解决。 【参考方案1】:

你可以使用类似configurator的回调模式,比如

struct TextView: UIViewRepresentable 
  @ObservedObject var config: ConfigModel = .shared
  @Binding var text: String
  
  @State var isEditable: Bool
  var borderColor: UIColor
  var borderWidth: CGFloat
  var configurator: ((UITextView) -> ())?     // << here !!

  func makeCoordinator() -> Coordinator 
    Coordinator(self)
  
  
  func makeUIView(context: Context) -> UITextView 
    let myTextView = UITextView()
    myTextView.delegate = context.coordinator
    
    myTextView.isScrollEnabled = true
    myTextView.isEditable = isEditable
    myTextView.isUserInteractionEnabled = true
    myTextView.layer.borderColor = borderColor.cgColor
    myTextView.layer.borderWidth = borderWidth
    myTextView.layer.cornerRadius = 8
    return myTextView
  

  func updateUIView(_ uiView: UITextView, context: Context) 
    uiView.font = uiView.font?.withSize(CGFloat(config.textsize))
    uiView.text = text

    // alternat is to call this function in makeUIView, which is called once,
    // and the store externally to send methods directly.
    configurator?(myTextView)                  // << here !!
  

  // ... other code

并在您的 SwiftUI 视图中使用它,例如

TextView(...)  uiText in
   uiText.isEditing = some

注意:根据您的情况,可能需要额外的条件来避免更新循环,不确定。

【讨论】:

以上是关于Swiftui - 从 UIViewRepresentable 访问 UIKit 方法/属性的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 将数据从 UIViewRepresentable 传递给 SwiftUI 的 View

SwiftUI之从前端视角看SwiftUI语言

从 SwiftUI 推送到 UIViewController

从 SpriteKit 场景移动到 SwiftUI 视图

从 SwiftUI 视图呈现 UIActivityViewController

从 UIKit 调整 SwiftUI 组件