如何在UITextView中添加占位符,类似于你可以为UITextField设置的占位符,在Swift中?
当前回答
import UIKit
import RxSwift
@IBDesignable class TextViewWithPlaceholder: UITextView {
//MARK: - Propertise
@IBInspectable var placeholderText: String = ""
let placeholderLabel = LocalizedUILabel()
private let hidePlaceholderObserver = PublishSubject<Bool>()
let disposeBag = DisposeBag()
//MARK: - Did Move To Window
override func didMoveToWindow() {
super.didMoveToWindow()
observeOnTextViewEditing()
configurePlaceholder()
}
//MARK: - Observe On Text View Editing
private func observeOnTextViewEditing() {
rx.text.subscribe(onNext: { [weak self] selectedText in
guard let self = self else { return }
self.hidePlaceholderObserver.onNext((selectedText?.isEmpty ?? true) ? false : true)
}).disposed(by: disposeBag)
}
//MARK: - Observe On Show Hide Placeholder
private func configurePlaceholder() {
hidePlaceholderObserver
.bind(to: placeholderLabel.rx.isHidden)
.disposed(by: disposeBag)
placeholderLabel.text = placeholderText
placeholderLabel.font = UIFont(name: "Poppins-Semibold", size: 16) ?? UIFont()
placeholderLabel.textColor = .lightGray
placeholderLabel.sizeToFit()
placeholderLabel.frame.origin = CGPoint(x: 8, y: 8)
addSubview(placeholderLabel)
}
}
其他回答
我通过使用两个不同的文本视图来做到这一点:
一个在后台用作占位符。 一个在前台(具有透明背景),用户实际输入。
其思想是,一旦用户开始在前景视图中输入内容,后台的占位符就会消失(如果用户删除了所有内容,则会重新出现)。因此,它的行为完全类似于单行文本字段的占位符。
这是我用的代码。注意,descriptionField是用户键入的字段,descriptionPlaceholder是后台的字段。
func textViewDidChange(descriptionField: UITextView) {
if descriptionField.text.isEmpty == false {
descriptionPlaceholder.text = ""
} else {
descriptionPlaceholder.text = descriptionPlaceholderText
}
}
这里有一些东西可以被放到UIStackView中,它会使用内部高度约束来调整自己的大小。可能需要调整以适应特定的需求。
import UIKit
public protocol PlaceholderTextViewDelegate: class {
func placeholderTextViewTextChanged(_ textView: PlaceholderTextView, text: String)
}
public class PlaceholderTextView: UIView {
public weak var delegate: PlaceholderTextViewDelegate?
private var heightConstraint: NSLayoutConstraint?
public override init(frame: CGRect) {
self.allowsNewLines = true
super.init(frame: frame)
self.heightConstraint = self.heightAnchor.constraint(equalToConstant: 0)
self.heightConstraint?.isActive = true
self.addSubview(self.placeholderTextView)
self.addSubview(self.textView)
self.pinToCorners(self.placeholderTextView)
self.pinToCorners(self.textView)
self.updateHeight()
}
public override func didMoveToSuperview() {
super.didMoveToSuperview()
self.updateHeight()
}
private func pinToCorners(_ view: UIView) {
NSLayoutConstraint.activate([
view.leadingAnchor.constraint(equalTo: self.leadingAnchor),
view.trailingAnchor.constraint(equalTo: self.trailingAnchor),
view.topAnchor.constraint(equalTo: self.topAnchor),
view.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
// Accessors
public var text: String? {
didSet {
self.textView.text = text
self.textViewDidChange(self.textView)
self.updateHeight()
}
}
public var textColor: UIColor? {
didSet {
self.textView.textColor = textColor
self.updateHeight()
}
}
public var font: UIFont? {
didSet {
self.textView.font = font
self.placeholderTextView.font = font
self.updateHeight()
}
}
public override var tintColor: UIColor? {
didSet {
self.textView.tintColor = tintColor
self.placeholderTextView.tintColor = tintColor
}
}
public var placeholderText: String? {
didSet {
self.placeholderTextView.text = placeholderText
self.updateHeight()
}
}
public var placeholderTextColor: UIColor? {
didSet {
self.placeholderTextView.textColor = placeholderTextColor
self.updateHeight()
}
}
public var allowsNewLines: Bool
public required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private lazy var textView: UITextView = self.newTextView()
private lazy var placeholderTextView: UITextView = self.newTextView()
private func newTextView() -> UITextView {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isScrollEnabled = false
textView.delegate = self
textView.backgroundColor = .clear
return textView
}
private func updateHeight() {
let maxSize = CGSize(width: self.frame.size.width, height: .greatestFiniteMagnitude)
let textViewSize = self.textView.sizeThatFits(maxSize)
let placeholderSize = self.placeholderTextView.sizeThatFits(maxSize)
let maxHeight = ceil(CGFloat.maximum(textViewSize.height, placeholderSize.height))
self.heightConstraint?.constant = maxHeight
}
}
extension PlaceholderTextView: UITextViewDelegate {
public func textViewDidChangeSelection(_: UITextView) {
self.placeholderTextView.alpha = self.textView.text.isEmpty ? 1 : 0
self.updateHeight()
}
public func textViewDidChange(_: UITextView) {
self.delegate?.placeholderTextViewTextChanged(self, text: self.textView.text)
}
public func textView(_: UITextView, shouldChangeTextIn _: NSRange,
replacementText text: String) -> Bool {
let containsNewLines = text.rangeOfCharacter(from: .newlines)?.isEmpty == .some(false)
guard !containsNewLines || self.allowsNewLines else { return false }
return true
}
}
与这篇文章中几乎所有的答案相反,UITextView确实有一个占位符属性。由于我无法理解的原因,它只在IB中出现,例如:
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="placeholder" value="My Placeholder"/>
</userDefinedRuntimeAttributes>
因此,如果你正在使用故事板,一个静态占位符就足够了,只需在检查器上设置属性。
你也可以像这样在代码中设置这个属性:
textView.setValue("My Placeholder", forKeyPath: "placeholder")
它的多云天气,这是通过私有API访问,因为属性是暴露的。
我还没有尝试过用这种方法提交。但我将很快以这种方式提交,并将相应地更新这个答案。
更新:
我已经在多个版本中发布了这个代码,苹果没有任何问题。
更新: 这将只适用于Xcode pre 11.2
迅速:
以编程方式或通过Interface Builder添加你的文本视图,如果是最后一个,创建outlet:
@IBOutlet weak var yourTextView: UITextView!
请添加委托(UITextViewDelegate):
class ViewController: UIViewController, UITextViewDelegate {
在viewDidLoad方法中,添加如下内容:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
yourTextView.delegate = self
yourTextView.text = "Placeholder text goes right here..."
yourTextView.textColor = UIColor.lightGray
现在让我来介绍一下神奇的部分,添加这个函数:
func textViewDidBeginEditing(_ textView: UITextView) {
if yourTextView.textColor == UIColor.lightGray {
yourTextView.text = ""
yourTextView.textColor = UIColor.black
}
}
请注意,这将在编辑开始时执行,在那里我们将检查条件来告知状态,使用color属性。 设置文本为nil我不建议。在此之后,我们将文本颜色设置为所需的颜色,在本例中为黑色。
现在也添加这个函数:
func textViewDidEndEditing(_ textView: UITextView) {
if yourTextView.text == "" {
yourTextView.text = "Placeholder text ..."
yourTextView.textColor = UIColor.lightGray
}
}
让我坚持一下,不要与零进行比较,我已经试过了,它不会起作用。然后我们将值设置回占位符样式,并将颜色设置回占位符颜色,因为这是在textViewDidBeginEditing中检查的条件。
Swift -我写了一个继承了UITextView的类,并添加了一个UILabel作为子视图作为占位符。
import UIKit
@IBDesignable
class HintedTextView: UITextView {
@IBInspectable var hintText: String = "hintText" {
didSet{
hintLabel.text = hintText
}
}
private lazy var hintLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFontOfSize(16)
label.textColor = UIColor.lightGrayColor()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupView()
}
private func setupView() {
translatesAutoresizingMaskIntoConstraints = false
delegate = self
font = UIFont.systemFontOfSize(16)
addSubview(hintLabel)
NSLayoutConstraint.activateConstraints([
hintLabel.leftAnchor.constraintEqualToAnchor(leftAnchor, constant: 4),
hintLabel.rightAnchor.constraintEqualToAnchor(rightAnchor, constant: 8),
hintLabel.topAnchor.constraintEqualToAnchor(topAnchor, constant: 4),
hintLabel.heightAnchor.constraintEqualToConstant(30)
])
}
override func layoutSubviews() {
super.layoutSubviews()
setupView()
}
}
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- 如何舍入一个双到最近的Int在迅速?
- 扁平化数组的数组在Swift
- Swift:声明一个空字典
- 在成功提交我的应用程序后,“太多符号文件”
- 从数组中随机选择一个元素
- 首先添加一个UIView,甚至是导航栏
- 我如何改变UIButton标题颜色?
- 在Swift中如何调用GCD主线程上的参数方法?
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- CFNetwork SSLHandshake iOS 9失败
- swift语言中的结构与类