Как поместить курсор в начало текста заполнителя в UITextview

Я потратил много времени, пытаясь исправить эту простую проблему, но не справился. Я хочу, чтобы в UITextView использовался заполнитель: «перевод», и при нажатии на UITextView заполнитель должен оставаться там до тех пор, пока не будет введен символ, но мне нужно, чтобы курсор был помещен в начало заполнителя непосредственно перед словом «перевод», но он остается в конце моего заполнителя. Я нашел несколько ответов и попытался сделать это следующим образом, но не работает. Заполнитель правильно меняется на черный цвет, но вторая команда -> textView.selectedRange = NSMakeRange(0, 0) не перемещает курсор в начало, почему?

  • Я заменил эту строку NSMakeRange следующей (другое предложение, которое я прочитал, но тот же результат, не работает) -> textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

Вот полный код:

class MainViewController: UIViewController, UITextViewDelegate, UITextFieldDelegate {
    


    @IBOutlet weak var definitionField: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // setting placeholder
        definitionField.textColor = .gray
        definitionField.text = "translation"
        
        definitionField.delegate = self    }
    
    
    func textViewDidBeginEditing(_ textView: UITextView) {
        if (textView.text == "translation") {

            textView.textColor = .black
            textView.selectedRange = NSMakeRange(0, 0)
        }
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        if (textView.text == "") {
           textView.text = "translation"
           textView.textColor = .gray
        }
        textView.resignFirstResponder()
    }

Первоначально я ответил на это, предлагая использовать placeholder, потому что я перепутал UITextField с UITextView. У первого есть заполнитель, но OP использует последний. я удалил свой ответ

Geoff Hackworth 17.04.2023 13:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Похоже, что selectedTextRange автоматически устанавливается системой после textViewDidBeginEditing и вызывается becomeFirstResponder. Вы можете наблюдать это, используя собственный подкласс UITextView и переопределяя:

override var selectedTextRange: UITextRange? {
    didSet {
        print(selectedTextRange)
    }
}

Вы увидите, что это сначала устанавливается на (0, 0) из-за вашего кода, а затем didSet снова "волшебным образом" вызывается, устанавливая selectedTextRange на (11, 0).

Я не уверен, какой метод сделал вызов. После этого может даже не быть переопределяемого метода.

Простым решением было бы просто использовать DispatchQueue.main.async, чтобы дождаться того, что установит выделенный текстовый диапазон в конец, а затем изменить выделение.

// in textViewDidBeginEditing
DispatchQueue.main.async {
    textView.selectedRange = NSMakeRange(0, 0)
}

Курсор появится в конце на короткое время, прежде чем перейти к началу. Кажется, это только визуально. Когда я пытался ввести текст, когда курсор находится в конце, текст вставляется перед «переводом».

Тем не менее, ваша реализация этого заполнителя, похоже, сильно отличается от того, как можно было бы ожидать, что заполнитель будет работать (например, в UITextField), особенно когда textViewDidEndEditing.

Если вам нужно поведение, похожее на UITextField, или если вы хотите увидеть другие подходы, ознакомьтесь с этим постом.

Спасибо, эффективно с DispatchQueue он работает с этим очень коротким временем, когда курсор появляется в конце. Сообщение, которым вы поделились, работает лучше, но единственный недостаток заключается в том, что после прикосновения к textView заполнитель мгновенно исчезает.

Dude1313 17.04.2023 19:52

Самое простое решение здесь — добавить метку, содержащую заполнитель. Затем установите его свойство isHidden в зависимости от того, есть ли текст в текстовом представлении.

Вот рабочий пример но он использует RxSwift для отслеживания изменений текста, цвета и шрифта.

Что оно делает:

  1. создайте метку и вставьте ее в текстовое представление в нужном месте.
  2. отслеживайте tintColor текстового представления и обновляйте textColor метки.
  3. следить за шрифтом текстового представления и обновлять шрифт метки.
  4. отслеживать текст текстового представления и обновлять свойство isHidden метки в зависимости от наличия текста.
extension UITextView {
    func withPlaceholder(_ placeholder: String) {
        let label = {
            let result = UILabel(frame: bounds)
            result.text = placeholder
            result.numberOfLines = 0
            result.frame = result.frame.offsetBy(dx: 4, dy: 8)
            return result
        }()

        addSubview(label)

        _ = rx.observe(UIColor.self, "tintColor")
            .take(until: rx.deallocating)
            .bind(to: label.rx.textColor)

        _ = rx.observe(UIFont.self, "font")
            .map { $0 != nil ? $0 : UIFont.systemFont(ofSize: 12) }
            .take(until: rx.deallocating)
            .bind(onNext: { [weak self] font in
                label.font = font
                label.frame.size = label.sizeThatFits(self?.bounds.size ?? CGSize.zero)
            })

        _ = rx.text.orEmpty.map { !$0.isEmpty }
            .take(until: rx.deallocating)
            .bind(to: label.rx.isHidden)
    }
}

Другие вопросы по теме