[英]Placeholder text inside UITextView in Swift
我做了一些研究,發現了這篇文章: 在 Swift 中的 UITextView 中添加占位符文本?
將上述示例合並到我的代碼中,我在一個空白的 xcode UIKit 項目中有以下內容:
import UIKit
class ViewController: UIViewController {
var sampleTextView = UITextView()
let placeholderText = "Type Something"
let placeholderTextColor = UIColor.lightGray
let normalTextColor = UIColor.label
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGray
sampleTextView.delegate = self
sampleTextView.text = placeholderText
sampleTextView.textColor = placeholderTextColor
sampleTextView.becomeFirstResponder()
sampleTextView.selectedTextRange = sampleTextView.textRange(from: sampleTextView.beginningOfDocument, to: sampleTextView.beginningOfDocument)
view.addSubview(sampleTextView)
sampleTextView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
sampleTextView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0),
sampleTextView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10),
sampleTextView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10),
sampleTextView.heightAnchor.constraint(equalToConstant: 100)
])
}
}
extension ViewController: UITextViewDelegate {
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = placeholderText
textView.textColor = placeholderTextColor
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Combine the textView text and the replacement text to
// create the updated text string
let currentText:String = textView.text
let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)
// If updated text view will be empty, add the placeholder
// and set the cursor to the beginning of the text view
if updatedText.isEmpty {
textView.text = placeholderText
textView.textColor = placeholderTextColor
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
// Else if the text view's placeholder is showing and the
// length of the replacement string is greater than 0, set
// the text color to black then set its text to the
// replacement string
else if textView.textColor == placeholderTextColor && !text.isEmpty {
textView.textColor = normalTextColor
textView.text = text
}
// For every other case, the text should change with the usual
// behavior...
else {
return true
}
// ...otherwise return false since the updates have already
// been made
return false
}
func textViewDidChangeSelection(_ textView: UITextView) {
if self.view.window != nil {
if textView.textColor == placeholderTextColor {
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
}
}
}
但是我有兩個錯誤,對於我的生活,我無法解決:
抱歉,如果這些是基本的,但我很難過。
情侶筆記...
我認為Shift沒有被釋放,因為你從shouldChangeTextIn range
返回False
......所以shouldChangeTextIn range
沒有與鍵盤完全通信。
至於重復的預測文本……我遇到過類似的問題。 我的印象是文本已經插入,並且在調用shouldChangeTextIn range
時設置了一個新的.selectedRange
。 所以代碼(如所寫)復制了它。
由於這些(和其他)復雜性,這里有一個使用CATextLayer
作為“占位符”文本的示例:
class PlaceHolderTestViewController: UIViewController, UITextViewDelegate {
var sampleTextView = UITextView()
let placeholderText = "Type Something"
let placeholderTextColor = UIColor.lightGray
let normalTextColor = UIColor.label
let textLayer = CATextLayer()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGray
if self.navigationController != nil {
// add a "Done" navigation bar button
let btn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTap))
self.navigationItem.rightBarButtonItem = btn
}
view.addSubview(sampleTextView)
sampleTextView.translatesAutoresizingMaskIntoConstraints = false
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
sampleTextView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40),
sampleTextView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 10),
sampleTextView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -10),
sampleTextView.heightAnchor.constraint(equalToConstant: 100)
])
sampleTextView.font = .systemFont(ofSize: 16.0)
// textLayer properties
textLayer.contentsScale = UIScreen.main.scale
textLayer.alignmentMode = .left
textLayer.isWrapped = true
textLayer.foregroundColor = placeholderTextColor.cgColor
textLayer.string = placeholderText
if let fnt = sampleTextView.font {
textLayer.fontSize = fnt.pointSize
} else {
textLayer.fontSize = 12.0
}
// insert the textLayer
sampleTextView.layer.insertSublayer(textLayer, at: 0)
// set delegate to self
sampleTextView.delegate = self
}
func textViewDidChange(_ textView: UITextView) {
textLayer.opacity = textView.text.isEmpty ? 1.0 : 0.0
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// update textLayer frame here
textLayer.frame = sampleTextView.bounds.insetBy(
dx: sampleTextView.textContainerInset.left + sampleTextView.textContainer.lineFragmentPadding,
dy: sampleTextView.textContainerInset.top
)
}
@objc func doneTap() -> Void {
view.endEditing(true)
}
}
並且,這是一個子類化UITextView
以使其更易於重用的示例 - 以及輕松地一次允許多個 textView:
class PlaceholderTextView: UITextView, UITextViewDelegate {
private let textLayer = CATextLayer()
public var placeholderText: String = "" {
didSet {
textLayer.string = placeholderText
setNeedsLayout()
}
}
public var placeholderTextColor: UIColor = .lightGray {
didSet {
textLayer.foregroundColor = placeholderTextColor.cgColor
setNeedsLayout()
}
}
override var font: UIFont? {
didSet {
if let fnt = self.font {
textLayer.fontSize = fnt.pointSize
} else {
textLayer.fontSize = 12.0
}
}
}
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() -> Void {
// textLayer properties
textLayer.contentsScale = UIScreen.main.scale
textLayer.alignmentMode = .left
textLayer.isWrapped = true
textLayer.foregroundColor = placeholderTextColor.cgColor
if let fnt = self.font {
textLayer.fontSize = fnt.pointSize
} else {
textLayer.fontSize = 12.0
}
// insert the textLayer
layer.insertSublayer(textLayer, at: 0)
// set delegate to self
delegate = self
}
override func layoutSubviews() {
super.layoutSubviews()
textLayer.frame = bounds.insetBy(
dx: textContainerInset.left + textContainer.lineFragmentPadding,
dy: textContainerInset.top
)
}
func textViewDidChange(_ textView: UITextView) {
// show / hide the textLayer
textLayer.opacity = textView.text.isEmpty ? 1.0 : 0.0
}
}
class PlaceHolderTestViewController: UIViewController {
let sampleTextView = PlaceholderTextView()
let placeholderText = "Type Something"
let placeholderTextColor = UIColor.lightGray
let normalTextColor = UIColor.label
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGray
if self.navigationController != nil {
// add a "Done" navigation bar button
let btn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTap))
self.navigationItem.rightBarButtonItem = btn
}
view.addSubview(sampleTextView)
sampleTextView.translatesAutoresizingMaskIntoConstraints = false
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
sampleTextView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40),
sampleTextView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 10),
sampleTextView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -10),
sampleTextView.heightAnchor.constraint(equalToConstant: 100)
])
sampleTextView.font = .systemFont(ofSize: 16.0)
sampleTextView.textColor = normalTextColor
sampleTextView.placeholderTextColor = placeholderTextColor
sampleTextView.placeholderText = placeholderText
}
@objc func doneTap() -> Void {
view.endEditing(true)
}
}
注意——這只是示例代碼,不應被視為“生產就緒”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.