我花了很多时间试图解决这个简单的问题,但没有成功。我想在 UITextView 中使用一个占位符:“翻译”,当点击 UITextView 时,占位符应该留在那里,直到输入一个字符,但我需要将光标放在占位符的开头,就在“翻译”字之前,但它保持不变在我的占位符的末尾。我找到了几个答案并尝试按照以下方式进行但不起作用。占位符正确更改为黑色,但第二个命令 -> textView.selectedRange = NSMakeRange(0, 0) 没有将光标移动到开头,为什么?
这里是完整的代码:
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()
}
看起来
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
的行为,或者如果您想查看其他方法,请查看这篇文章。
这里最简单的解决方案是添加一个包含占位符的标签。然后根据文本视图中是否有文本来设置它的
isHidden
属性
这是一个工作示例,但它使用 RxSwift 来跟踪文本、颜色和字体更改。
它的作用:
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)
}
}