如何在UITextView中添加占位符,类似于你可以为UITextField设置的占位符,在Swift中?
当前回答
我相信这是一个非常干净的解决方案。它在实际文本视图下面添加了一个虚拟文本视图,并根据实际文本视图中的文本显示或隐藏它:
import Foundation
import UIKit
class TextViewWithPlaceholder: UITextView {
private var placeholderTextView: UITextView = UITextView()
var placeholder: String? {
didSet {
placeholderTextView.text = placeholder
}
}
override var text: String! {
didSet {
placeholderTextView.isHidden = text.isEmpty == false
}
}
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
applyCommonTextViewAttributes(to: self)
configureMainTextView()
addPlaceholderTextView()
NotificationCenter.default.addObserver(self,
selector: #selector(textDidChange),
name: UITextView.textDidChangeNotification,
object: nil)
}
func addPlaceholderTextView() {
applyCommonTextViewAttributes(to: placeholderTextView)
configurePlaceholderTextView()
insertSubview(placeholderTextView, at: 0)
}
private func applyCommonTextViewAttributes(to textView: UITextView) {
textView.translatesAutoresizingMaskIntoConstraints = false
textView.textContainer.lineFragmentPadding = 0
textView.textContainerInset = UIEdgeInsets(top: 10,
left: 10,
bottom: 10,
right: 10)
}
private func configureMainTextView() {
// Do any configuration of the actual text view here
}
private func configurePlaceholderTextView() {
placeholderTextView.text = placeholder
placeholderTextView.font = font
placeholderTextView.textColor = UIColor.lightGray
placeholderTextView.frame = bounds
placeholderTextView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
override func layoutSubviews() {
super.layoutSubviews()
placeholderTextView.frame = bounds
}
@objc func textDidChange() {
placeholderTextView.isHidden = !text.isEmpty
}
}
其他回答
我很惊讶没有人提到NSTextStorageDelegate。UITextViewDelegate的方法只能由用户交互触发,而不是以编程方式触发。例如,当你以编程方式设置一个文本视图的文本属性时,你必须自己设置占位符的可见性,因为委派方法不会被调用。
然而,使用NSTextStorageDelegate的textStorage(_:didProcessEditing:range:changeInLength:)方法,你会收到任何文本更改的通知,即使它是通过编程完成的。就像这样分配它:
textView.textStorage.delegate = self
(在UITextView中,这个委派属性默认为nil,所以它不会影响任何默认行为。)
将它与@clearlight演示的UILabel技术结合起来,可以轻松地将整个UITextView的占位符实现包装成一个扩展。
extension UITextView {
private class PlaceholderLabel: UILabel { }
private var placeholderLabel: PlaceholderLabel {
if let label = subviews.compactMap( { $0 as? PlaceholderLabel }).first {
return label
} else {
let label = PlaceholderLabel(frame: .zero)
label.font = font
addSubview(label)
return label
}
}
@IBInspectable
var placeholder: String {
get {
return subviews.compactMap( { $0 as? PlaceholderLabel }).first?.text ?? ""
}
set {
let placeholderLabel = self.placeholderLabel
placeholderLabel.text = newValue
placeholderLabel.numberOfLines = 0
let width = frame.width - textContainer.lineFragmentPadding * 2
let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
placeholderLabel.frame.size.height = size.height
placeholderLabel.frame.size.width = width
placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)
textStorage.delegate = self
}
}
}
extension UITextView: NSTextStorageDelegate {
public func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorageEditActions, range editedRange: NSRange, changeInLength delta: Int) {
if editedMask.contains(.editedCharacters) {
placeholderLabel.isHidden = !text.isEmpty
}
}
}
注意,使用了一个名为PlaceholderLabel的私有(嵌套)类。它根本没有实现,但它为我们提供了一种识别占位符标签的方法,这比使用tag属性要“快捷”得多。
使用这种方法,你仍然可以将UITextView的委托分配给其他人。
你甚至不需要改变文本视图的类。只要添加扩展,你就可以为项目中的每个UITextView分配一个占位符字符串,甚至在接口生成器中也是如此。
出于清晰的原因,我省略了placeholderColor属性的实现,但是它可以用与placeholder类似的计算变量在多几行中实现。
斯威夫特
这是一个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)
我们可以很容易地实现textview占位符,如果我们正在使用pod IQKeyboardManagerSwift在我们的项目中,只需遵循4个步骤
我们必须将类IQTextView分配给我们的TextView类。 我们必须在Controller页面中导入IQKeyboardManagerSwift 最后但并非最不重要的是,在控制器页面的textView的出口//如果你想:) 通过storyboard inspectable给textView一些占位符文本
在swift2.2:
public class CustomTextView: UITextView {
private struct Constants {
static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()
private var placeholderLabelConstraints = [NSLayoutConstraint]()
@IBInspectable public var placeholder: String = "" {
didSet {
placeholderLabel.text = placeholder
}
}
@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
didSet {
placeholderLabel.textColor = placeholderColor
}
}
override public var font: UIFont! {
didSet {
placeholderLabel.font = font
}
}
override public var textAlignment: NSTextAlignment {
didSet {
placeholderLabel.textAlignment = textAlignment
}
}
override public var text: String! {
didSet {
textDidChange()
}
}
override public var attributedText: NSAttributedString! {
didSet {
textDidChange()
}
}
override public var textContainerInset: UIEdgeInsets {
didSet {
updateConstraintsForPlaceholderLabel()
}
}
override public init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(textDidChange),
name: UITextViewTextDidChangeNotification,
object: nil)
placeholderLabel.font = font
placeholderLabel.textColor = placeholderColor
placeholderLabel.textAlignment = textAlignment
placeholderLabel.text = placeholder
placeholderLabel.numberOfLines = 0
placeholderLabel.backgroundColor = UIColor.clearColor()
placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(placeholderLabel)
updateConstraintsForPlaceholderLabel()
}
private func updateConstraintsForPlaceholderLabel() {
var newConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|-(\(textContainerInset.top))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints.append(NSLayoutConstraint(
item: placeholderLabel,
attribute: .Width,
relatedBy: .Equal,
toItem: self,
attribute: .Width,
multiplier: 1.0,
constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
))
removeConstraints(placeholderLabelConstraints)
addConstraints(newConstraints)
placeholderLabelConstraints = newConstraints
}
@objc private func textDidChange() {
placeholderLabel.hidden = !text.isEmpty
}
public override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UITextViewTextDidChangeNotification,
object: nil)
}
}
在swift3:
import UIKit
类 CustomTextView: { UITextView
private struct Constants {
static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()
private var placeholderLabelConstraints = [NSLayoutConstraint]()
@IBInspectable public var placeholder: String = "" {
didSet {
placeholderLabel.text = placeholder
}
}
@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
didSet {
placeholderLabel.textColor = placeholderColor
}
}
override public var font: UIFont! {
didSet {
placeholderLabel.font = font
}
}
override public var textAlignment: NSTextAlignment {
didSet {
placeholderLabel.textAlignment = textAlignment
}
}
override public var text: String! {
didSet {
textDidChange()
}
}
override public var attributedText: NSAttributedString! {
didSet {
textDidChange()
}
}
override public var textContainerInset: UIEdgeInsets {
didSet {
updateConstraintsForPlaceholderLabel()
}
}
override public init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
NotificationCenter.default.addObserver(self,
selector: #selector(textDidChange),
name: NSNotification.Name.UITextViewTextDidChange,
object: nil)
placeholderLabel.font = font
placeholderLabel.textColor = placeholderColor
placeholderLabel.textAlignment = textAlignment
placeholderLabel.text = placeholder
placeholderLabel.numberOfLines = 0
placeholderLabel.backgroundColor = UIColor.clear
placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(placeholderLabel)
updateConstraintsForPlaceholderLabel()
}
private func updateConstraintsForPlaceholderLabel() {
var newConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|-(\(textContainerInset.top))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints.append(NSLayoutConstraint(
item: placeholderLabel,
attribute: .width,
relatedBy: .equal,
toItem: self,
attribute: .width,
multiplier: 1.0,
constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
))
removeConstraints(placeholderLabelConstraints)
addConstraints(newConstraints)
placeholderLabelConstraints = newConstraints
}
@objc private func textDidChange() {
placeholderLabel.isHidden = !text.isEmpty
}
public override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}
deinit {
NotificationCenter.default.removeObserver(self,
name: NSNotification.Name.UITextViewTextDidChange,
object: nil)
}
}
我用swift写了一个类。您需要在需要的时候导入这个类。
浮动的占位符
将占位符标签放置在文本视图之上,通过跟踪文本视图字符计数的变化来设置其字体、颜色和管理占位符可见性,这是简单、安全且可靠的。
斯威夫特5:
class NotesViewController : UIViewController {
@IBOutlet var textView : UITextView!
var placeholderLabel : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
placeholderLabel = UILabel()
placeholderLabel.text = "Enter some text..."
placeholderLabel.font = .italicSystemFont(ofSize: (textView.font?.pointSize)!)
placeholderLabel.sizeToFit()
textView.addSubview(placeholderLabel)
placeholderLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)
placeholderLabel.textColor = .tertiaryLabel
placeholderLabel.isHidden = !textView.text.isEmpty
}
}
extension NotesViewController : UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
placeholderLabel.isHidden = !textView.text.isEmpty
}
}
推荐文章
- 我应该如何从字符串中删除所有的前导空格?- - - - - -斯威夫特
- 如何使用Xcode创建。ipa文件?
- 动态改变UILabel的字体大小
- 在iPhone上确定用户是否启用了推送通知
- 是否有可能禁用浮动头在UITableView与UITableViewStylePlain?
- Swift:理解// MARK
- 错误ITMS-9000:“冗余二进制文件上传。火车1.0版本已经有一个二进制版本上传。
- Swift -转换为绝对值
- Swift编译器错误:“框架模块内的非模块化头”
- 从父iOS访问容器视图控制器
- 自定义dealloc和ARC (Objective-C)
- 调整UITableView的大小以适应内容
- 在代码中为UIButton设置一个图像
- NSRange从Swift Range?
- 我可以使用范围操作符与if语句在Swift?