【问题标题】:How to get the Character that is before the cursor in a UITextView?如何获取 UITextView 中光标之前的字符?
【发布时间】:2018-09-26 10:04:18
【问题描述】:

假设我有以下UITextView 对象:

var textView = UITextView()
textView.text = "Hello World!"

现在假设我不想让用户在编辑时删除“W”字符。我怎么知道光标之前是哪个字符(或被它选中)?

我正在寻找可以像这样工作的东西:

if textView.characterBeforeCursor() != "W" {
   textView.deleteBackward()
}

或...(当用户选择“W”字符时):

if textView.selectedTextContains("W") == false {
   textView.deleteBackward()
}

我应该使用什么方法来实现这一点?

【问题讨论】:

  • 如何检查修改前后'W`的长度,如果有差异则返回textView之前的值?
  • 我想过这种可能性,但它看起来像一个“黑客”。我想知道是否有这样做的“正确方法”。
  • 你试过 - developer.apple.com/documentation/uikit/uitextfielddelegate/… 吗?您可以对范围进行一些计算,也可以控制输入。为您拍摄的完美照片。
  • 您的意思是您想知道单词的第一个字母(以空格分隔)是否即将更改?并阻止它?还是在这种情况下只是“W”?

标签: ios swift uitextview


【解决方案1】:

这是一个想法,尚未经过全面测试,但似乎可行...只需抓住即将被执行的角色并阻止退格,如果它是目标...同样关于文本的选择,如果选择包含完全没有目标,我们阻止新文本。

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.textView.delegate = self
        // Do any additional setup after loading the view, typically from a nib.
    }

    func characterBeforeCursor() -> String? {
        // get the cursor position
        if let cursorRange = textView.selectedTextRange {
            // get the position one character before the cursor start position
            if let newPosition = textView.position(from: cursorRange.start, offset: -1) {
                let range = textView.textRange(from: newPosition, to: cursorRange.start)
                return textView.text(in: range!)
            }
        }
        return nil
    }

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if (characterBeforeCursor() == "W") {
            let char = text.cString(using: String.Encoding.utf8)!
            let isBackSpace = strcmp(char, "\\b")
            if (isBackSpace == -92) {
                return false
            }
            return true
        }
        else {
            if let range = textView.selectedTextRange {
                let selectedText = textView.text(in: range)
                if (selectedText!.contains("W")) {
                    return false
                }
            }
            return true
        }
    }
}

【讨论】:

  • @ThiagoAM - 现在它已更新,即使在选择时也可以使用
  • @ThiagoAM - 有一个错误,但它现在可以工作,我认为它很好,检查一下
  • 很好的答案!这就是我要找的,谢谢!
  • @ThiagoAM 您是否尝试过其他较短的答案或至少阅读过它们?
  • @ThiagoAM 很高兴!
【解决方案2】:

应该这样做:

let forbiddenLetter = "W" 

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    guard let txt = textView.text, let txtRange = Range(range, in: txt) else {
        return false
    }

    let subString: Substring = txt[txtRange]

    return !subString.contains(forbiddenLetter)
}

在上面的代码中let txt = textView.text 只是为了简单起见,我们可以继续强制解包textView.text!,因为.text 属性被设计为永远不会为非零UITextView 返回nil

通过let txtRange = Range(range, in: txt),我们得到一个Range<String.Index> 类型的变量,而不是range 的普通NSRange。通过这样做,我们可以获得 textView 即将更改的txt 的子字符串。

最后返回检查subString是否包含forbiddenLetter的结果。


这个 sn-p 会阻止删除 W 使用:

  • 退格键
  • 删除选择
  • 粘贴选择
  • 自动更正(从弹出窗口中)

【讨论】:

  • 发现问题,您的解决方案使用 UITextField 委托方法,而不是 UITextView
  • @Woodstock 感谢您指出这一点,我已经更新了答案
  • 这是一个华丽的解决方案,应该标记为答案。做得好,你能注释你的代码以显示逻辑吗?
猜你喜欢
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 2011-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多