将光标定位在UITextView占位符文本的开头位置。

huangapple go评论69阅读模式
英文:

How to position the cursor at the beginning of the placeholder text in UITextview

问题

I spent a lot of time trying to fix this simple issues but don't managed it. I want in UITextView to use a placeholder: "translation" and when tapping the UITextView the placeholder should stay there until a character is entered but I need the cursor to be placed at the beginning of the placeholder just before "translation" word but it stays at the end of my placeholder. I find several answers and tried to do it as following but doesn't work. The placeholder changes correctly to black color but the 2nd command -> textView.selectedRange = NSMakeRange(0, 0) is not moving the cursor to the beginning, why?

  • I replaced this NSMakeRange line with following (other suggestion I read but same result, doesn't work) -> textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

Here the full code:

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()
    }
}
英文:

I spent a lot of time trying to fix this simple issues but don't managed it. I want in UITextView to use a placeholder: "translation" and when tapping the UITextView the placeholder should stay there until a character is entered but I need the cursor to be placed at the beginning of the placeholder just before "translation" word but it stays at the end of my placeholder. I find several answers and tried to do it as following but doesn't work. The placeholder changes correctly to black colour but the 2nd command -> textView.selectedRange = NSMakeRange(0, 0) is not moving the cursor to the beginning, why?

  • I replaced this NSMakeRange line with following (other suggestion I read but same result, doesn't work) -> textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

Here the full code:

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()
    }

答案1

得分: 1

以下是您要翻译的内容:

"selectedTextRange" 在 "textViewDidBeginEditing" 被调用之后,系统会自动设置,并且在调用 "becomeFirstResponder" 后也会设置。您可以通过使用自定义的 "UITextView" 子类并覆盖以下代码来观察:

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

您将看到,由于您的代码,它首先被设置为 "(0, 0)",然后 "didSet" 会被“神奇地”再次调用,将 "selectedTextRange" 设置为 "(11, 0)"。

我不确定是哪个方法进行了调用。甚至可能没有一个可重写的方法在此之后被调用。

一个简单的解决方案是只需使用 "DispatchQueue.main.async" 来等待设置所选文本范围的任何操作完成,然后再更改选择范围。

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

光标会在最后出现一小段时间,然后回到开头。这似乎只是视觉效果。当我尝试在光标位于末尾时输入文本时,文本会在“翻译”之前插入。

话虽如此,您对这个占位符的实现似乎与人们期望的占位符工作方式有很大不同(就像 "UITextField" 中的占位符),尤其是在 "textViewDidEndEditing" 时。

如果您希望实现类似于 "UITextField" 的行为,或者想要查看其他方法,请参阅 此帖子

英文:

It appears that selectedTextRange is being set automatically by the system, after textViewDidBeginEditing, and becomeFirstResponder is called. You can observe this by using a custom UITextView subclass, and overriding:

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

You will see that this first gets set to (0, 0) because of your code, and then didSet is "magically" called again, setting selectedTextRange to (11, 0).

I'm not sure which method did the call. There might not even be a overridable method that gets called after that.

A simple solution would be to just use DispatchQueue.main.async to wait for whatever is setting the selected text range to the end, and then change the selection.

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

The cursor will appear at the end for a brief moment, before going to the start. This seems to be only visual. When I tried to enter text when the cursor is at the end, the text is inserted before "translation".

That said, your implementation of this placeholder seems to have rather different from how one would expect a placeholder to work (like the one in UITextField), especially when textViewDidEndEditing.

If you want behaviours similar to UITextField, or if you want to see other approaches, check out this post.

答案2

得分: 0

以下是翻译好的内容:

最简单的解决方法是添加一个包含占位符的标签,然后根据文本视图中是否有任何文本来设置其 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)
	}
}
英文:

The simplest solution here is to add a label that holds the placeholder. Then set its isHidden property based on whether there is any text in the text view.

Here is a working example but it uses RxSwift to track text, color, and font changes.

What it does:

  1. create a label and embed it into the text view at the proper spot.
  2. monitor the tintColor of the text view and update the textColor of the label.
  3. monitor the font of the text view and update the font of the label.
  4. monitor the text of the text view and update the isHidden property of the label based on whether there is any text.
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)
	}
}

huangapple
  • 本文由 发表于 2023年4月17日 18:35:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76034222.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定