概要
UITextViewにプレースホルダーを追加してみました。
かつ、プレースホルダーには折り返しをしてくれるようにしてみました。
はじめに
UITextViewにプレースホルダーを追加するだけのやり方であれば、
パイセン等が分かりやすくて素晴らしい記事を公開されてるので、そちらを参考にしてみてください。
UITextViewにプレースホルダーを設定できるようにする(Swift4)
[Swift 4.2] UITextViewにプレースホルダーを追加する[iOS 12]
私自身も大変参考にさせて頂きました🙇♂️
ありがとうございます🙇♂️🙇♂️🙇♂️
というか、ほぼほぼベースはパクらせてもらっ
こんなの
まずはじめに、単純にプレースホルダーをUILabelで追加しただけであれば、
こんな感じに折り返しが効かずに見切れてしまっています。
※『UITextViewのPlaceHolderをここに表示してます。』という文言を設定
ソースコード
プレースホルダーの表示用として、UILabelをaddSubViewしており、
その際に、superViewであるUITextViewに対してAutolayoutの設定を入れることにより、折り返して表示してくれるようになってます。
import UIKit
@IBDesignable
class PlaceHolderTextView: UITextView {
private let placeHolderLabelEdgeInsets = UIEdgeInsets(top: 8, left: 5, bottom: 8, right: 5)
private var placeHolderLabelWidthAConstraint = NSLayoutConstraint()
private var placeHolderLabelWidth: CGFloat {
return frame.width - (placeHolderLabelEdgeInsets.left + placeHolderLabelEdgeInsets.right)
}
lazy private var placeHolderLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = font
label.backgroundColor = .clear
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
placeHolderLabelWidthAConstraint = label.widthAnchor.constraint(equalToConstant: placeHolderLabelWidth)
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: topAnchor, constant: placeHolderLabelEdgeInsets.top),
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: placeHolderLabelEdgeInsets.left)
])
return label
}()
@IBInspectable var placeHolder: String = "" {
didSet { reloadView() }
}
@IBInspectable var placeHolderColor: UIColor = .lightGray {
didSet { reloadView() }
}
override var text: String! {
didSet { changeVisiblePlaceHolder() }
}
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() {
changeVisiblePlaceHolder()
NotificationCenter.default.addObserver(self, selector: #selector(textChanged), name: UITextView.textDidChangeNotification, object: nil)
}
override func layoutSubviews() {
super.layoutSubviews()
placeHolderLabelWidthAConstraint.constant = placeHolderLabelWidth
placeHolderLabelWidthAConstraint.isActive = true
}
}
extension PlaceHolderTextView {
private func reloadView() {
placeHolderLabel.text = placeHolder
placeHolderLabel.textColor = placeHolderColor
changeVisiblePlaceHolder()
}
private func changeVisiblePlaceHolder() {
placeHolderLabel.isHidden = placeHolder.isEmpty || !text.isEmpty
}
@objc private func textChanged(notification: NSNotification?) {
changeVisiblePlaceHolder()
}
}
おわりに
そもそも、プレースホルダーに折り返しが必要になるほどの長文を書くシチュエーションに遭遇するのでしょうか・・・🤔
追記
@am10 さんからのご指摘&ご提案から、コードベースでテキスト代入時にもプレースホルダーの表示切替が可能になりました!
@yo1106 さんからのご指摘により、コードから生成時の不具合(そもそも考慮してなかった🙈)が発覚し、修正致しました。