如何在UITextView中添加占位符,类似于你可以为UITextField设置的占位符,在Swift中?
当前回答
这是我准备使用的解决方案,如果您正在处理多个文本视图
func textViewShouldBeginEditing(textView: UITextView) -> Bool {
// Set cursor to the beginning if placeholder is set
if textView.textColor == UIColor.lightGrayColor() {
textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
}
return true
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// Remove placeholder
if textView.textColor == UIColor.lightGrayColor() && text.characters.count > 0 {
textView.text = ""
textView.textColor = UIColor.blackColor()
}
if text == "\n" {
textView.resignFirstResponder()
return false
}
return true
}
func textViewDidChange(textView: UITextView) {
// Set placeholder if text is empty
if textView.text.isEmpty {
textView.text = NSLocalizedString("Hint", comment: "hint")
textView.textColor = UIColor.lightGrayColor()
textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
}
}
func textViewDidChangeSelection(textView: UITextView) {
// Set cursor to the beginning if placeholder is set
let firstPosition = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
// Do not change position recursively
if textView.textColor == UIColor.lightGrayColor() && textView.selectedTextRange != firstPosition {
textView.selectedTextRange = firstPosition
}
}
其他回答
我喜欢@nerdist的解决方案。在此基础上,我创建了UITextView的扩展:
import Foundation
import UIKit
extension UITextView
{
private func add(_ placeholder: UILabel) {
for view in self.subviews {
if let lbl = view as? UILabel {
if lbl.text == placeholder.text {
lbl.removeFromSuperview()
}
}
}
self.addSubview(placeholder)
}
func addPlaceholder(_ placeholder: UILabel?) {
if let ph = placeholder {
ph.numberOfLines = 0 // support for multiple lines
ph.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
ph.sizeToFit()
self.add(ph)
ph.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
ph.textColor = UIColor(white: 0, alpha: 0.3)
updateVisibility(ph)
}
}
func updateVisibility(_ placeHolder: UILabel?) {
if let ph = placeHolder {
ph.isHidden = !self.text.isEmpty
}
}
}
例如,在ViewController类中,我是这样使用它的:
class MyViewController: UIViewController, UITextViewDelegate {
private var notePlaceholder: UILabel!
@IBOutlet weak var txtNote: UITextView!
...
// UIViewController
override func viewDidLoad() {
notePlaceholder = UILabel()
notePlaceholder.text = "title\nsubtitle\nmore..."
txtNote.addPlaceholder(notePlaceholder)
...
}
// UITextViewDelegate
func textViewDidChange(_ textView: UITextView) {
txtNote.updateVisbility(notePlaceholder)
...
}
UITextview的占位符!
更新:
如果你在代码中改变textview的文本,记得调用updateVisibitly方法来隐藏占位符:
txtNote.text = "something in code"
txtNote.updateVisibility(self.notePlaceholder) // hide placeholder if text is not empty.
为了防止占位符被添加多次,在扩展中添加了一个私有add()函数。
以下是我解决这个问题的方法(Swift 4):
这个想法是做出最简单的解决方案,允许使用不同颜色的占位符,调整占位符大小,不会覆盖委托,同时保持所有UITextView函数正常工作。
import UIKit
class PlaceholderTextView: UITextView {
var placeholderColor: UIColor = .lightGray
var defaultTextColor: UIColor = .black
private var isShowingPlaceholder = false {
didSet {
if isShowingPlaceholder {
text = placeholder
textColor = placeholderColor
} else {
textColor = defaultTextColor
}
}
}
var placeholder: String? {
didSet {
isShowingPlaceholder = !hasText
}
}
@objc private func textViewDidBeginEditing(notification: Notification) {
textColor = defaultTextColor
if isShowingPlaceholder { text = nil }
}
@objc private func textViewDidEndEditing(notification: Notification) {
isShowingPlaceholder = !hasText
}
// MARK: - Construction -
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
NotificationCenter.default.addObserver(self, selector: #selector(textViewDidBeginEditing(notification:)), name: UITextView.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(textViewDidEndEditing(notification:)), name: UITextView.textDidEndEditingNotification, object: nil)
}
// MARK: - Destruction -
deinit { NotificationCenter.default.removeObserver(self) }
}
斯威夫特
这是一个Swiftui TextView使用UIVIewRepresentable,具有占位符功能和边界颜色
struct TextView: UIViewRepresentable {
@Binding var text: String
var placeholderText: String
var textStyle: UIFont.TextStyle
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.font = UIFont.preferredFont(forTextStyle: textStyle)
textView.autocapitalizationType = .sentences
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.delegate = context.coordinator
textView.layer.borderWidth = 0.6
textView.layer.borderColor = UIColor.lightGray.cgColor
textView.layer.cornerRadius = 10
textView.text = placeholderText
textView.textColor = UIColor.lightGray
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
uiView.font = UIFont.preferredFont(forTextStyle: textStyle)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextViewDelegate {
var parent: TextView
init(_ parent: TextView) {
self.parent = parent
}
func textViewDidChange(_ textView: UITextView) {
self.parent.text = textView.text
}
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.textColor == UIColor.lightGray {
textView.text = nil
textView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = self.parent.placeholderText
textView.textColor = UIColor.lightGray
}
}
}
}
然后在你的视图中你可以这样使用它
TextView(text: self.$viewModel.addPostCommentText, placeholderText: "Share your story about this cash", textStyle: .body)
.padding()
.frame(height: 150)
我通过使用两个不同的文本视图来做到这一点:
一个在后台用作占位符。 一个在前台(具有透明背景),用户实际输入。
其思想是,一旦用户开始在前景视图中输入内容,后台的占位符就会消失(如果用户删除了所有内容,则会重新出现)。因此,它的行为完全类似于单行文本字段的占位符。
这是我用的代码。注意,descriptionField是用户键入的字段,descriptionPlaceholder是后台的字段。
func textViewDidChange(descriptionField: UITextView) {
if descriptionField.text.isEmpty == false {
descriptionPlaceholder.text = ""
} else {
descriptionPlaceholder.text = descriptionPlaceholderText
}
}
这是我用来完成这项工作的方法。
@IBDesignable class UIPlaceholderTextView: UITextView {
var placeholderLabel: UILabel?
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
sharedInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sharedInit()
}
override func prepareForInterfaceBuilder() {
sharedInit()
}
func sharedInit() {
refreshPlaceholder()
NotificationCenter.default.addObserver(self, selector: #selector(textChanged), name: UITextView.textDidChangeNotification, object: nil)
}
@IBInspectable var placeholder: String? {
didSet {
refreshPlaceholder()
}
}
@IBInspectable var placeholderColor: UIColor? = .darkGray {
didSet {
refreshPlaceholder()
}
}
@IBInspectable var placeholderFontSize: CGFloat = 14 {
didSet {
refreshPlaceholder()
}
}
func refreshPlaceholder() {
if placeholderLabel == nil {
placeholderLabel = UILabel()
let contentView = self.subviews.first ?? self
contentView.addSubview(placeholderLabel!)
placeholderLabel?.translatesAutoresizingMaskIntoConstraints = false
placeholderLabel?.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: textContainerInset.left + 4).isActive = true
placeholderLabel?.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: textContainerInset.right + 4).isActive = true
placeholderLabel?.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textContainerInset.top).isActive = true
placeholderLabel?.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: textContainerInset.bottom).isActive = true
}
placeholderLabel?.text = placeholder
placeholderLabel?.textColor = placeholderColor
placeholderLabel?.font = UIFont.systemFont(ofSize: placeholderFontSize)
}
@objc func textChanged() {
if self.placeholder?.isEmpty ?? true {
return
}
UIView.animate(withDuration: 0.25) {
if self.text.isEmpty {
self.placeholderLabel?.alpha = 1.0
} else {
self.placeholderLabel?.alpha = 0.0
}
}
}
override var text: String! {
didSet {
textChanged()
}
}
}
我知道有很多类似的方法,但这个方法的好处是:
在IB中设置占位符文本、字体大小和颜色。 在IB中不再显示“滚动视图有不明确的可滚动内容”的警告。 添加动画显示/隐藏占位符。
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- 如何舍入一个双到最近的Int在迅速?
- 扁平化数组的数组在Swift
- Swift:声明一个空字典
- 在成功提交我的应用程序后,“太多符号文件”
- 从数组中随机选择一个元素
- 首先添加一个UIView,甚至是导航栏
- 我如何改变UIButton标题颜色?
- 在Swift中如何调用GCD主线程上的参数方法?
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- CFNetwork SSLHandshake iOS 9失败
- swift语言中的结构与类