在子类和UIViewController中使用UITextViewDelegate

时间:2016-03-26 20:22:06

标签: ios swift2 uitextview

我是子类化UITextView并在子类中实现一些委托方法,如textViewDidChangeSelection,但我还需要在View Controller中获取UITextView委托的通知。 因此,如果我在视图控制器中创建子类的对象并设置textview委托,则仅在视图控制器中通知委托方法而不在子类内部。我需要通知这两个班级。我正在使用的语言是swift 2

我试图在子类委托中继承UITextViewDelegate:

@objc protocol CustomTextViewDelegate:UITextViewDelegate {

    func customTextViewDidChangeSize(chatTextView: CustomTextView)

}

然后在VC中:

let customTV = CustomTextView()
customTV.customTextViewDelegate = self

但是没有调用任何textview委托方法。

3 个答案:

答案 0 :(得分:1)

好问题。这不是一个很好的答案,因为它要求您重写所有委托方法,因此,如果委托方法随时间变化,则在iOS版本之间不稳定。

通过这种方法,ViewControllerCustomTextField都可以访问委托事件。

class CustomTextView: UITextView {
   override var delegate: UITextViewDelegate? {
      set {
         superDelegate = newValue
      } get {
         return superDelegate
      }
    }

    private weak var superDelegate: UITextViewDelegate?

    init() {
       super.init(frame: .zero, textContainer: nil)
       super.delegate = self
    }

    func textDidChange(text: String?) {
        // do something
    }

}

extension BoundTextView: UITextViewDelegate {
    public func textViewDidChange(_ textView: UITextView) {
        // catch text-change events here
        textDidChange(text: String?) 
        superDelegate?.textViewDidChange?(textView)
    }

    public func textViewDidEndEditing(_ textView: UITextView) {
        superDelegate?.textViewDidEndEditing?(textView)
    }

    public func textViewDidChangeSelection(_ textView: UITextView) {
        superDelegate?.textViewDidChange?(textView)
    }

    public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
       return superDelegate?.textViewShouldBeginEditing?(textView) ?? false
    }

    public func textViewDidBeginEditing(_ textView: UITextView) {
        superDelegate?.textViewDidBeginEditing?(textView)
    }

    public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
       return superDelegate?.textViewShouldEndEditing?(textView) ?? false
    }

    public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        return superDelegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? false
    }

    public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        return superDelegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction: interaction) ?? false
    }

    public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        return superDelegate?.textView?(textView, shouldInteractWith: textAttachment, in: characterRange, interaction: interaction) ?? false
    }
}

我们重写delegate并将其引用存储在单独的变量(称为superDelegate)中。 CustomTextField将自身分配给super.delegate并实现UITextView-delegate。我们必须确保每个委托事件都会触发相应的superDelegate事件。

我们的“ ViewController”现在可以将自己分配为CustomTextView的委托人:

class ViewController: UIViewController {

   ...
   lazy var textField: CustomTextView {
      let textView = CustomTextField()
      textView.delegate = self 
      return textField
   }()
   ...


}

extension ViewController: UITextViewDelegate {

   // implement only the delegate-methods you need

}

现在ViewControllerCustomTextField都可以访问UITextFieldDelegate

答案 1 :(得分:0)

两个对象不能同时委托给UITextView对象。因此,您应为CustomTextViewDelegate创建新协议(CustomTextView)并在其中创建委托属性。让您的ViewController确认此CustomTextViewDelegate并实施其方法。在CustomTextView UITextViewDelegate方法的实施中,您可以调用适当的CustomTextViewDelegate方法。

答案 2 :(得分:0)

@nayooti 的方法非常好。但是,我必须做一些修复才能正常工作。主要的问题是某些委托方法不会被调用(例如 shouldChangeTextIn range,因此 textViewDidChange 也是如此)。

我发现可以通过在覆盖的 super.delegate 变量的 get 访问器上返回 superDelegate 而不是 delegate 来修复它。

class CustomTextView: UITextView {
    
    override var delegate: UITextViewDelegate? {
        set {
            superDelegate = newValue
        } get {
            return super.delegate
        }
    }
    
    private weak var superDelegate: UITextViewDelegate?
    
    init() {
        super.init(frame: .zero, textContainer: nil)
        super.delegate = self
    }
    
    override public init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        super.delegate = self
    }
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        super.delegate = self
    }
    
    func textDidChange(text: String?) {
        // Do something
    }
    
}

extension CustomTextView: UITextViewDelegate {
    
    public func textViewDidChange(_ textView: UITextView) {
        // Catch text-change events here
        textDidChange(text: textView.text)
        superDelegate?.textViewDidChange?(textView)
    }
    
    public func textViewDidEndEditing(_ textView: UITextView) {
        superDelegate?.textViewDidEndEditing?(textView)
    }
    
    public func textViewDidChangeSelection(_ textView: UITextView) {
        superDelegate?.textViewDidChange?(textView)
    }
    
    public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
        return superDelegate?.textViewShouldBeginEditing?(textView) ?? true
    }
    
    public func textViewDidBeginEditing(_ textView: UITextView) {
        superDelegate?.textViewDidBeginEditing?(textView)
    }
    
    public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
        return superDelegate?.textViewShouldEndEditing?(textView) ?? true
    }
    
    public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        return superDelegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? true
    }
    
    public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        return superDelegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction: interaction) ?? true
    }
    
    public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        return superDelegate?.textView?(textView, shouldInteractWith: textAttachment, in: characterRange, interaction: interaction) ?? true
    }
    
}