Удаление Slide-to-type by word в UITextView дает неверный диапазон в методе делегата `shouldChangeText` - PullRequest
1 голос
/ 06 апреля 2020

У меня есть UITextView в ViewController. Я реализовал shouldChangeTextInRange метод делегата из UITextViewDelegate . Значение range , которое я получаю с помощью вышеуказанного метода делегата для удаления одного символа, выглядит примерно так: {location, 1} .

Но если я использую механизм слайд-типа для вставки слова перед выполнением операции удаления, все слово удаляется вместо одного символа. Мне нужно следить за этим.

Например, я вставляю «Hello», используя механизм слайд-типа. Если я нажимаю клавишу удаления на клавиатуре, я получаю {4, 1} в качестве диапазона, но все слово «Hello» было удалено в текстовом представлении. В этом случае мне нужно, чтобы диапазон был {0, 5}, очень похоже на выделение текста «Hello» и его удаление.

Есть ли способ различить обычную операцию удаления и удаление по типу слайда операция? Как я могу получить фактический диапазон, который был удален в текстовом представлении?

Небольшая помощь очень ценится.

Это то, что я пробовал.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.addTextView()
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }
}

extension ViewController {
    func addTextView() {
        let textContainer = NSTextContainer(size: CGSize(width: 200, height: CGFloat.greatestFiniteMagnitude))

        let layoutManager = NSLayoutManager()
        layoutManager.addTextContainer(textContainer)

        let textStorage = NSTextStorage()
        textStorage.delegate = self
        textStorage.addLayoutManager(layoutManager)

        let textViewFrame = CGRect(x: 50, y: 50, width: 200, height: 200)
        let textView = UITextView(frame: textViewFrame, textContainer: textContainer)
        textView.backgroundColor = .green
        textView.delegate = self

        self.view.addSubview(textView)
    }
}

extension ViewController: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        print("text editing began")
    }

    func textViewDidChange(_ textView: UITextView) {
        print("text view content changed")
    }

    func textViewDidChangeSelection(_ textView: UITextView) {
        print("text view selection changed")
    }

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        print("should change \(text) in \(range)")
        return true
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        print("text editing ended")
    }
}

extension ViewController: NSTextStorageDelegate {
    func textStorage(_ textStorage: NSTextStorage, willProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {
        print("will process \(editedRange)")
    }

    func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {
        print("did process \(editedRange)")
    }
}

РЕДАКТ. 1:

У меня есть отдельный механизм хранения, в котором я обновляю изменения, внесенные в текстовое представление, на основе диапазона и текста замены, предоставленного в shouldChangeText метод делегата. Я не включил это ради простоты.

1 Ответ

0 голосов
/ 02 мая 2020

Я только что заметил одно и то же и долго боролся, пытаясь понять это элегантно. Мне кажется, что это должно быть ошибкой, так что, надеюсь, это будет исправлено в ближайшее время. Я отправлю отчет об ошибке в Apple после того, как отправлю решение, которое придумаю.

Во-первых, нам нужен способ отслеживать, когда пользователь мог удалить целое слово (т. Е. В любое время, когда он удалил). все, что мы должны проверить, если они удалили более одного символа). Мы можем сделать это методом UITextViewDelegate textView(_:shouldChangeTextIn:replacementText:). Мы знаем, что что-то было удалено , когда замещающий текст пуст (т. Е. text.count == 0).

// Variable to keep track of when a word might have been deleted
fileprivate var didJustDelete = false


func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
  if text.count > 0 {
    // Code to handle adding text
    ...
  } else {
    // Code to handle deleting text
    didJustDelete = true
    ...
  }
}

Затем в textViewDidChange (другое UITextViewDelegate метод) мы можем определить разницу и обработать ее соответственно.

func textViewDidChange(_ textView: UITextView) {
  // Check for deleting an entire word
  if didJustDelete {
    didJustDelete = false

    let difference = actualText.count - textView.text.count
    if difference > 0 {
      // Code to handle deleting a word
      let range = NSRange(location: textView.text.count, length: difference)
      ...
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...