【问题标题】:Swift 4 - How do I test for TextView content did change?Swift 4 - 我如何测试 TextView 内容是否发生了变化?
【发布时间】:2025-05-21 03:30:02
【问题描述】:

Swift 4、iOS 11 - 我有一个 UITextView,它预先填充了文本,但我希望用户能够保存他们对那里的内容所做的任何更改。我在导航栏中也有一个保存按钮,我想禁用它,直到用户实际更改 TextView 中的文本。

我知道如何测试是否为空,但我不知道如何测试文本何时被编辑。如何修改以下内容以测试 TextView 内容的更改?

@IBAction func textEditingChanged(_ sender: UITextView) {
    updateSaveButtonState()
  }

func updateSaveButtonState() {
    let descriptionText = descriptionTextView.text ?? ""
    saveButton.isEnabled = !descriptionText.isEmpty
  }

【问题讨论】:

  • 使用自定义的isEdited 布尔值,在-textViewDidChange(_:) 方法中变成true 并在保存更改后变成false
  • holex,您的 isEdited 布尔值听起来像是朝着正确的方向发展。你能详细说明一下吗?

标签: uitextview ios11 swift4 xcode9


【解决方案1】:

我们将以动态的方式使用它,而不仅仅是在单个地方,我试图使其更容易在整个应用程序中实现,将UITextView 子类化是@holex 建议的唯一方法之一isEdited boolean flag,它给了我一个想法,谢谢。

以下是实现它的步骤:

首先设置 textView 的 defaultText 并设置 textView 将被编辑时将调用的方法的目标,这样你就可以自定义任何你想要的。

@IBOutlet weak var saveButton: UIBarButtonItem!
@IBOutlet weak var textView: SBTextView!{
    didSet{
        textView.defaultText = "Hello"
        textView.setTarget = (selector:#selector(self.updateSaveButtonState),target:self)
    }
}

假设您将在 viewDidLoad 中设置 saveButton:

override func viewDidLoad() {
    super.viewDidLoad()

    // setup save button action
    saveButton.action = #selector(saveAction(_:))
    saveButton.target = self
    self.updateSaveButtonState()

}

最后是您的保存操作和使用isEdited 标志更新视图的选择器。

//MARK:- Actions

@objc private func updateSaveButtonState(){

    // has not been changed keep save button disabled
    if self.textView.isEdited == false{
        self.saveButton.isEnabled = false
        self.saveButton.tintColor = .gray
    }else {
        // text has been changed enable save button
        self.saveButton.isEnabled = true
        self.saveButton.tintColor = nil // will reset the color to default
    }
}

@objc private func saveAction(_ saveButton:UIBarButtonItem){

    self.textView.updateDefaultText()

}

TextView 自定义类:

//
//  SBTextView.swift
//
//
//  Created by Saad Albasha on 11/17/17.
//  Copyright © 2017 AaoIi. All rights reserved.
//

import UIKit

class SBTextView: UITextView,UITextViewDelegate {

    var isEdited = false
    private var selector : Selector?
    private var target : UIViewController?
    var setTarget: (selector:Selector?,target:UIViewController?) {
        get{
            return (selector,target)
        }
        set(newVal) {
            selector = newVal.0
            target = newVal.1
        }
    }
    var textViewDefaultText = ""
    var defaultText: String {
        get {
            return textViewDefaultText
        }
        set(newVal) {
            textViewDefaultText = newVal
            self.text = newVal
            self.isEdited = false
        }
    }

    //MARK:- Life Cycle

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)

        self.setupTextview()

    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.setupTextview()
    }

    private func setupTextview(){

        // setup textview
        self.text = textViewDefaultText
        self.delegate = self

    }

    func updateDefaultText(){

        self.defaultText = self.text!

        // update save button state
        target!.perform(self.selector, with: nil, with: nil)
    }

    //MARK:- Delegate

    internal func textViewDidChange(_ textView: UITextView) {

        if textViewDefaultText != textView.text! {
            isEdited = true
        }else {
            isEdited = false
        }

        // update save button state
        target!.perform(self.selector, with: nil, with: nil)
    }

}

我希望这会有所帮助。

【讨论】:

  • Aaoli,感谢您的详细回复。在您回复的最开始,它说要保留默认值的引用。但是,应用程序中每个 TextView 的默认值是多个段落,并且每个场景都不同。这似乎使得无法利用此选项。无论内容如何,​​是否都没有“观察” TextView 更改的选项?
  • @fmz 好吧,这就是我从您的问题中了解到的,您需要在多个地方使用它并不是很清楚,因此您只有一种可能的方法是子类 @987654328 @,你想让我为你做一个这样的东西吗?
  • @fmz 我已经更新了我的答案,让我知道它是否适合你
最近更新 更多