こんにちは、nukkyです。
UITextFieldにはプレースホルダが標準で用意されていますが、UITextViewには用意されていません。
そこで、今回はUITextViewにプレースホルダっぽいものを表示できるようなクラスを作成したいと思います!
Xcode 9.1
iOS 11 Simulator
Swift 4.0
まずはUITextViewを継承したクラスを作成します。
プレースホルダをStoryboard上で確認するために@IBDesignableを宣言します。
import UIKit @IBDesignable class PlaceHolderTextView: UITextView {
プレースホルダ表示用のUILabelを用意します
private lazy var placeHolderLabel: UILabel = UILabel(frame: CGRect(x: 6.0, y: 6.0, width: 0.0, height: 0.0))
プレースホルダ表示用のUILabelを構築します
private func configurePlaceHolder() { self.placeHolderLabel.lineBreakMode = .byWordWrapping self.placeHolderLabel.font = self.font self.placeHolderLabel.textColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22) self.placeHolderLabel.backgroundColor = .clear self.addSubview(placeHolderLabel) }
プレースホルダの表示/非表示を切り替えるメソッドを用意します
private func changeVisiblePlaceHolder() { if self.placeHolder.isEmpty || !self.text.isEmpty { self.placeHolderLabel.alpha = 0.0 } else { self.placeHolderLabel.alpha = 1.0 } }
プレースホルダを用意するということはキーボードを表示し入力すると思うので、UITextViewは改行に対応しているためコードでキーボードのUIToolbarに閉じるボタンを追加します
private func setToolBar() { // 仮のサイズでツールバー生成 let kbToolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 40)) kbToolBar.barStyle = UIBarStyle.default // スタイルを設定 kbToolBar.sizeToFit() // 画面幅に合わせてサイズを変更 // スペーサー let spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: self, action: nil) // 閉じるボタン let commitButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(PlaceHolderTextView.commitButtonTapped)) kbToolBar.items = [spacer, commitButton] self.inputAccessoryView = kbToolBar } @objc private func commitButtonTapped (){ self.endEditing(true) }
awakeFromNibで上記のメソッドをよんでおきます、それとこのタイミングでプレースホルダの表示/非表示を切り替えるためにNotificationCenterからUITextViewTextDidChangeを検知するようにします
override func awakeFromNib() { super.awakeFromNib() self.configurePlaceHolder() self.changeVisiblePlaceHolder() self.setToolBar() NotificationCenter.default.addObserver(self, selector: #selector(textChanged), name: .UITextViewTextDidChange, object: nil) } @objc private func textChanged(notification: NSNotification?) { changeVisiblePlaceHolder() } deinit { NotificationCenter.default.removeObserver(self) }
最後にStoryboardからプレースホルダを編集できるように@IBInspectableを用意します
@IBInspectable var placeHolder: String = "" { didSet { self.placeHolderLabel.text = self.placeHolder self.placeHolderLabel.numberOfLines = 0 self.placeHolderLabel.sizeToFit() } }
これでUITextViewにプレースホルダっぽいものを表示できるようになります!
個人的には結構UITextViewにプレースホルダをつけたい機会は多いと思っているので同じような思いをしている人のお役に立てればと。