SwiftのUITextView内にプレースホルダーテキストを追加するにはどうすればよいですか?


316

を使用するアプリケーションを作成していますUITextView。次に、テキストビューに、テキストフィールドに設定できるプレースホルダーと同様のプレースホルダーを設定します。Swiftを使用してこれをどのように達成しますか?


これは、UITextViewを使用したiOS開発における古くからの問題です。ここで言及したようなサブクラスを書きました:stackoverflow.com/a/1704469/1403046。利点は、ロジックを再実装することなく、デリゲートを保持したり、クラスを複数の場所で使用したりできることです。
cjwirth 2014

プロジェクトにswiftを使用しているときに、サブクラスをどのように使用しますか?ブリッジファイルを使用していますか?
StevenR

それを行うか、Swiftで再実装できます。回答のコードは、実際に必要な長さよりも長くなっています。主なポイントは、テキストが変更されたときに通知されるメソッドに追加するラベルを表示/非表示にすることです。
cjwirth 2014

GitHubのUIFloatLabelTextViewサンプルを使用できます。書き込み中は、この位置のプレースホルダーが上になります。本当に面白い!github.com/ArtSabintsev/UIFloatLabelTextView
Jayprakash Dubey

2
正直なところ、これを達成する最も簡単な方法は、カスタムのtextViewを用意し、テキストが存在しないときにtextViewに描画されるプレースホルダーテキストを追加することです。状態管理(テキストが存在するべき/存在すべきでない/存在しない場合の
誤検知を含む

回答:


649

Swift 4用に更新

UITextViewには本質的にプレースホルダープロパティがないため、UITextViewDelegateメソッドを使用してプログラムで1つを作成して操作する必要があります。目的の動作に応じて、以下のソリューション#1または#2を使用することをお勧めします。

注:どちらのソリューションでUITextViewDelegateも、クラスに追加しtextView.delegate = self、テキストビューのデリゲートメソッドを使用するように設定します。


解決策#1-ユーザーがテキストビューを選択するとすぐにプレースホルダーを非表示にする場合:

最初にUITextViewプレースホルダーテキストを含むように設定し、それを薄い灰色に設定して、プレースホルダーテキストの外観を模倣しUITextFieldます。どちらかでそうviewDidLoadか、テキストビューの作成時。

textView.text = "Placeholder"
textView.textColor = UIColor.lightGray

次に、ユーザーがテキストビューの編集を開始したときに、テキストビューにプレースホルダーが含まれている場合(つまり、テキストの色が薄い灰色の場合)、ユーザーの入力に対応するためにプレースホルダーテキストをクリアし、テキストの色を黒に設定します。

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 = "Placeholder"
        textView.textColor = UIColor.lightGray
    }
}

解決策#2-テキストビューが選択されている場合でも、テキストビューが空の場合は常にプレースホルダーを表示する場合:

最初にプレースホルダーを設定しますviewDidLoad

textView.text = "Placeholder"
textView.textColor = UIColor.lightGray

textView.becomeFirstResponder()

textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

(注:OPはビューが読み込まれるとすぐにテキストビューを選択する必要があるため、上記のコードにテキストビュー選択を組み込みました。これが望ましい動作ではなく、ビューの読み込み時にテキストビューを選択したくない場合は、上記のコードチャンクから最後の2行を削除します。)

次にshouldChangeTextInRange UITextViewDelegate、次のようにメソッドを利用します。

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    // Combine the textView text and the replacement text to
    // create the updated text string
    let currentText:String = textView.text
    let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)

    // If updated text view will be empty, add the placeholder
    // and set the cursor to the beginning of the text view
    if updatedText.isEmpty {

        textView.text = "Placeholder"
        textView.textColor = UIColor.lightGray

        textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
    }

    // Else if the text view's placeholder is showing and the
    // length of the replacement string is greater than 0, set 
    // the text color to black then set its text to the
    // replacement string
     else if textView.textColor == UIColor.lightGray && !text.isEmpty {
        textView.textColor = UIColor.black
        textView.text = text
    }

    // For every other case, the text should change with the usual
    // behavior...
    else {
        return true
    }

    // ...otherwise return false since the updates have already
    // been made
    return false
}

またtextViewDidChangeSelection、プレースホルダーが表示されているときにユーザーがカーソルの位置を変更できないように実装します。(注:textViewDidChangeSelectionビューが読み込まれる前に呼び出されるため、ウィンドウが表示されている場合にのみテキストビューの色を確認します):

func textViewDidChangeSelection(_ textView: UITextView) {
    if self.view.window != nil {
        if textView.textColor == UIColor.lightGray {
            textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
        }
    }
}

5
こんにちは。textControllerのデリゲートとしてビューコントローラ設定してください。これは、textViewからviewControllerへのアウトレットを作成することで実現できます。次にを使用しますyourTextField.delegate = self。これを行わないと、textViewDidBeginEditingおよびtextViewDidEndEditing関数は機能しません。
Ujjwal-Nadhani 2016

2
コードがコンパイルされていませんCannot convert value of type 'NSRange' (aka '_NSRange') to expected argument type 'Range<String.Index>' (aka 'Range<String.CharacterView.Index>')。エラーが発生しています。
iPeter 2017年

4
解決策を見つけたので、改訂したコード@iPeterを添付します。現在のテキストはNSStringフォルマントでなければなりません:let currentText = textView.text as NSString?let updatedText =線をに変換しlet updatedText = currentText?.replacingCharacters(in: range, with: text)ます。最後に、if updatedText.isEmptyラインをに変換しif (updatedText?.isEmpty)! {ます。これでうまくいくはずです!
ベイラーミッチェル

1
@TàTruhoadaコピーと貼り付けのシナリオを処理するようにソリューションを更新しました
Lyndsey Scott

3
@LyndseyScottを内側textView.selectedTextRangeから設定するfunc textViewDidChangeSelection(_ textView: UITextView)と、無限ループが発生します...
MikeG

229

フローティングプレースホルダー


テキストビューの上にプレースホルダーラベルを配置し、そのフォント、色を設定し、テキストビューの文字数の変化を追跡することでプレースホルダーの可視性を管理するのは、簡単、安全、そして信頼できます。

スウィフト3:

class NotesViewController : UIViewController, UITextViewDelegate {

    @IBOutlet var textView : UITextView!
    var placeholderLabel : UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.delegate = self
        placeholderLabel = UILabel()
        placeholderLabel.text = "Enter some text..."
        placeholderLabel.font = UIFont.italicSystemFont(ofSize: (textView.font?.pointSize)!)
        placeholderLabel.sizeToFit()
        textView.addSubview(placeholderLabel)
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !textView.text.isEmpty
    }

    func textViewDidChange(_ textView: UITextView) {
        placeholderLabel.isHidden = !textView.text.isEmpty
    }
}

スウィフト2:同じことは、除きます。italicSystemFontOfSize(textView.font.pointSize)UIColor.lightGrayColor



19
この方法は間違いなく、私が見つけた最も簡単でエラーが発生しにくい方法です。すばらしい。
デビッド

6
...それは良い方法ですが、プレースホルダーテキストが非常に長い場合には、ラベルのテキストがバインドの外出も
アクス

5
使いやすく、既存の動作とうまく統合されます。プレースホルダーメッセージはとにかく冗長であるべきではありませんが、行を0に設定してその問題に対処しないでください。
TommieC。

2
カーソルはプレースホルダーの左側ではなく上部に中央揃えされるため、テキストが中央揃えの場合は問題がありますが、私は一般的にこの方法を好みます。
blwinters 2017年

1
@blwinters-それは本当に珍しいコーナーケースでしょうね?しかし、その場合は複数行入力フィールドであると想定します(想定する必要があります)、垂直オフセットの計算を調整して、プレースホルダーテキストをカーソルから少し離れたところに移動できませんか?
クリアライト2017年

35

KMPlaceholderTextViewライブラリの使用を強くお勧めします。使い方はとても簡単。


1
これは、はるかに簡単な解決策です(UILabelsの追加や特別なデリゲート処理を行う必要はありません)。そのまま使用できます。
HixField 2016

うまくいくはずです。著者はそれがSwift
3.0+を

27

迅速:

プログラムで、またはInterface Builderを介してテキストビューを追加します。最後の場合は、アウトレットを作成します。

@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プロパティを使用して、状態を通知するための条件をチェックします。テキストをniliに設定することはお勧めしません。その直後に、テキストの色を希望の色(この場合は黒)に設定します。

次に、この関数も追加します。

func textViewDidEndEditing(_ textView: UITextView) {

    if yourTextView.text == "" {

        yourTextView.text = "Placeholder text ..."
        yourTextView.textColor = UIColor.lightGray
    }
}

私は主張しないでくださいnil、と比較しないでください、私はすでにそれを試しました、そしてそれはうまくいきません。次に、値をプレースホルダースタイルに戻し、色をプレースホルダーの色に戻しtextViewDidBeginEditingます。これは、チェックインする条件であるためです。


16

この拡張機能を使用すると、UITextViewでプレースホルダーを設定するのに最適な方法です。ただし、デリゲートがTextViewにアタッチされていることを確認してください。次のようにプレースホルダーを設定できます:-

yourTextView.placeholder = "Placeholder" 

extension UITextView :UITextViewDelegate
{

    /// Resize the placeholder when the UITextView bounds change
    override open var bounds: CGRect {
        didSet {
            self.resizePlaceholder()
        }
    }

    /// The UITextView placeholder text
    public var placeholder: String? {
        get {
            var placeholderText: String?

            if let placeholderLabel = self.viewWithTag(100) as? UILabel {
                placeholderText = placeholderLabel.text
            }

            return placeholderText
        }
        set {
            if let placeholderLabel = self.viewWithTag(100) as! UILabel? {
                placeholderLabel.text = newValue
                placeholderLabel.sizeToFit()
            } else {
                self.addPlaceholder(newValue!)
            }
        }
    }

    /// When the UITextView did change, show or hide the label based on if the UITextView is empty or not
    ///
    /// - Parameter textView: The UITextView that got updated
    public func textViewDidChange(_ textView: UITextView) {
        if let placeholderLabel = self.viewWithTag(100) as? UILabel {
            placeholderLabel.isHidden = self.text.characters.count > 0
        }
    }

    /// Resize the placeholder UILabel to make sure it's in the same position as the UITextView text
    private func resizePlaceholder() {
        if let placeholderLabel = self.viewWithTag(100) as! UILabel? {
            let labelX = self.textContainer.lineFragmentPadding
            let labelY = self.textContainerInset.top - 2
            let labelWidth = self.frame.width - (labelX * 2)
            let labelHeight = placeholderLabel.frame.height

            placeholderLabel.frame = CGRect(x: labelX, y: labelY, width: labelWidth, height: labelHeight)
        }
    }

    /// Adds a placeholder UILabel to this UITextView
    private func addPlaceholder(_ placeholderText: String) {
        let placeholderLabel = UILabel()

        placeholderLabel.text = placeholderText
        placeholderLabel.sizeToFit()

        placeholderLabel.font = self.font
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.tag = 100

        placeholderLabel.isHidden = self.text.characters.count > 0

        self.addSubview(placeholderLabel)
        self.resizePlaceholder()
        self.delegate = self
    }
}

1
チャームのように働いた!! ありがとうございます !:)
Nahid Raihan

Welcome Dear All the best
Sandip Gill

15

誰も言及しなかったことに驚いていNSTextStorageDelegateます。UITextViewDelegateのメソッドは、ユーザーの操作によってのみトリガーされ、プログラムではトリガーされません。たとえば、テキストビューのtextプロパティをプログラムで設定する場合は、デリゲートメソッドが呼び出されないため、プレースホルダーの可視性を自分で設定する必要があります。

ただし、NSTextStorageDelegatetextStorage(_:didProcessEditing:range:changeInLength:)メソッドを使用すると、プログラムで行われた場合でも、テキストへの変更が通知されます。次のように割り当てるだけです。

textView.textStorage.delegate = self

(ではUITextView、このデリゲートプロパティはnilデフォルトで設定されているため、デフォルトの動作には影響しません。)

UILabel@clearlightが示す手法と組み合わせると、全体UITextViewplaceholder実装を拡張機能に簡単にラップできます。

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


非常にエレガントなソリューション。大好きです。
Dave Batton、2018

textView.textStorage.delegate = selfビューコントローラーでこれを行うには、そのビューコントローラーをにバインドする必要がありNSTextStorageDelegateます。本当に必要ですか?
Hemang

シンプルで魅力のように動作します。これは受け入れられる必要がある回答
Qaiser Abbas

@HemangそれNSTextStorageDelegateはビューコントローラではなくテキストビューそのものです。
yesleon

14

2つの異なるテキストビューを使用してこれを行いました。

  1. プレースホルダーとして使用される背景の1つ。
  2. ユーザーが実際に入力するフォアグラウンドの1つ(背景が透明)。

アイデアは、ユーザーがフォアグラウンドビューで何かを入力し始めると、バックグラウンドのプレースホルダーが消える(そしてユーザーがすべてを削除すると再び表示される)というものです。したがって、1行のテキストフィールドのプレースホルダーとまったく同じように動作します。

これが私が使用したコードです。descriptionFieldはユーザーが入力するフィールドであり、descriptionPlaceholderはバックグラウンドのフィールドであることに注意してください。

func textViewDidChange(descriptionField: UITextView) {
    if descriptionField.text.isEmpty == false {
        descriptionPlaceholder.text = ""
    } else {
        descriptionPlaceholder.text = descriptionPlaceholderText
    }
}

1
この方法は少しハックですが、それははるかに簡単であり、あなたが望む結果を正確に生成します。良いアイデア
ウィリアムT.

9

ここですでにいくつかの素晴らしい提案に基づいて、私は次の軽量のInterface-Builder互換のサブクラスをまとめることができましUITextViewた。

  • と同じスタイルの設定可能なプレースホルダーテキストが含まれますUITextField
  • 追加のサブビューや制約は必要ありません。
  • ViewControllerからの委任やその他の動作は必要ありません。
  • 通知は必要ありません。
  • そのテキストを、フィールドのtextプロパティを参照する外部クラスから完全に分離します。

特にiOSのプレースホルダーの色をハードコーディングするのではなく、プログラムでプルする方法がある場合は、改善の提案を歓迎します。

Swift v5:

import UIKit
@IBDesignable class TextViewWithPlaceholder: UITextView {

    override var text: String! { // Ensures that the placeholder text is never returned as the field's text
        get {
            if showingPlaceholder {
                return "" // When showing the placeholder, there's no real text to return
            } else { return super.text }
        }
        set { super.text = newValue }
    }
    @IBInspectable var placeholderText: String = ""
    @IBInspectable var placeholderTextColor: UIColor = UIColor(red: 0.78, green: 0.78, blue: 0.80, alpha: 1.0) // Standard iOS placeholder color (#C7C7CD). See /programming/31057746/whats-the-default-color-for-placeholder-text-in-uitextfield
    private var showingPlaceholder: Bool = true // Keeps track of whether the field is currently showing a placeholder

    override func didMoveToWindow() {
        super.didMoveToWindow()
        if text.isEmpty {
            showPlaceholderText() // Load up the placeholder text when first appearing, but not if coming back to a view where text was already entered
        }
    }

    override func becomeFirstResponder() -> Bool {
        // If the current text is the placeholder, remove it
        if showingPlaceholder {
            text = nil
            textColor = nil // Put the text back to the default, unmodified color
            showingPlaceholder = false
        }
        return super.becomeFirstResponder()
    }

    override func resignFirstResponder() -> Bool {
        // If there's no text, put the placeholder back
        if text.isEmpty {
            showPlaceholderText()
        }
        return super.resignFirstResponder()
    }

    private func showPlaceholderText() {
        showingPlaceholder = true
        textColor = placeholderTextColor
        text = placeholderText
    }
}

6

ビューロードのSET値

    txtVw!.autocorrectionType = UITextAutocorrectionType.No
    txtVw!.text = "Write your Placeholder"
    txtVw!.textColor = UIColor.lightGrayColor()



func textViewDidBeginEditing(textView: UITextView) {
    if (txtVw?.text == "Write your Placeholder")

    {
        txtVw!.text = nil
        txtVw!.textColor = UIColor.blackColor()
    }
}

func textViewDidEndEditing(textView: UITextView) {
    if txtVw!.text.isEmpty
    {
        txtVw!.text = "Write your Placeholder"
        txtVw!.textColor = UIColor.lightGrayColor()
    }
    textView.resignFirstResponder()
}

6

clearlight答えからコードを使いやすくしようとしました。

extension UITextView{

    func setPlaceholder() {

        let placeholderLabel = UILabel()
        placeholderLabel.text = "Enter some text..."
        placeholderLabel.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
        placeholderLabel.sizeToFit()
        placeholderLabel.tag = 222
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !self.text.isEmpty

        self.addSubview(placeholderLabel)
    }

    func checkPlaceholder() {
        let placeholderLabel = self.viewWithTag(222) as! UILabel
        placeholderLabel.isHidden = !self.text.isEmpty
    }

}

使用法

override func viewDidLoad() {
    textView.delegate = self
    textView.setPlaceholder()
}

func textViewDidChange(_ textView: UITextView) {
    textView.checkPlaceholder()
}

いくつかの問題。(1)UIViewタグのプロパティ値を想定して「借用」する拡張機能として、誰かが拡張機能の使用法を認識せずに独自のビュー階層で同じタグを使用し、バグの診断が非常に困難になるリスクがあります。そのようなものは、ライブラリコードや拡張機能には属していません。(2)それでも、呼び出し元はデリゲートを宣言する必要があります。フローティングプレースホルダは、ハッキングを回避小さなフットプリントを持っている、それ安全な賭けになりた、シンプルかつ完全にローカルです。
クリアライト2017

5

もう1つの解決策(Swift 3):

import UIKit

protocol PlaceholderTextViewDelegate {
    func placeholderTextViewDidChangeText(_ text:String)
    func placeholderTextViewDidEndEditing(_ text:String)
}

final class PlaceholderTextView: UITextView {

    var notifier:PlaceholderTextViewDelegate?

    var placeholder: String? {
        didSet {
            placeholderLabel?.text = placeholder
        }
    }
    var placeholderColor = UIColor.lightGray
    var placeholderFont = UIFont.appMainFontForSize(14.0) {
        didSet {
            placeholderLabel?.font = placeholderFont
        }
    }

    fileprivate var placeholderLabel: UILabel?

    // MARK: - LifeCycle

    init() {
        super.init(frame: CGRect.zero, textContainer: nil)
        awakeFromNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        self.delegate = self
        NotificationCenter.default.addObserver(self, selector: #selector(PlaceholderTextView.textDidChangeHandler(notification:)), name: .UITextViewTextDidChange, object: nil)

        placeholderLabel = UILabel()
        placeholderLabel?.textColor = placeholderColor
        placeholderLabel?.text = placeholder
        placeholderLabel?.textAlignment = .left
        placeholderLabel?.numberOfLines = 0
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        placeholderLabel?.font = placeholderFont

        var height:CGFloat = placeholderFont.lineHeight
        if let data = placeholderLabel?.text {

            let expectedDefaultWidth:CGFloat = bounds.size.width
            let fontSize:CGFloat = placeholderFont.pointSize

            let textView = UITextView()
            textView.text = data
            textView.font = UIFont.appMainFontForSize(fontSize)
            let sizeForTextView = textView.sizeThatFits(CGSize(width: expectedDefaultWidth,
                                                               height: CGFloat.greatestFiniteMagnitude))
            let expectedTextViewHeight = sizeForTextView.height

            if expectedTextViewHeight > height {
                height = expectedTextViewHeight
            }
        }

        placeholderLabel?.frame = CGRect(x: 5, y: 0, width: bounds.size.width - 16, height: height)

        if text.isEmpty {
            addSubview(placeholderLabel!)
            bringSubview(toFront: placeholderLabel!)
        } else {
            placeholderLabel?.removeFromSuperview()
        }
    }

    func textDidChangeHandler(notification: Notification) {
        layoutSubviews()
    }

}

extension PlaceholderTextView : UITextViewDelegate {
    // MARK: - UITextViewDelegate
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if(text == "\n") {
            textView.resignFirstResponder()
            return false
        }
        return true
    }

    func textViewDidChange(_ textView: UITextView) {
        notifier?.placeholderTextViewDidChangeText(textView.text)
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        notifier?.placeholderTextViewDidEndEditing(textView.text)
    }
}

結果

ここに画像の説明を入力してください


4

私のために機能するシンプルで迅速な解決策は次のとおりです。

@IBDesignable
class PlaceHolderTextView: UITextView {

    @IBInspectable var placeholder: String = "" {
         didSet{
             updatePlaceHolder()
        }
    }

    @IBInspectable var placeholderColor: UIColor = UIColor.gray {
        didSet {
            updatePlaceHolder()
        }
    }

    private var originalTextColor = UIColor.darkText
    private var originalText: String = ""

    private func updatePlaceHolder() {

        if self.text == "" || self.text == placeholder  {

            self.text = placeholder
            self.textColor = placeholderColor
            if let color = self.textColor {

                self.originalTextColor = color
            }
            self.originalText = ""
        } else {
            self.textColor = self.originalTextColor
            self.originalText = self.text
        }

    }

    override func becomeFirstResponder() -> Bool {
        let result = super.becomeFirstResponder()
        self.text = self.originalText
        self.textColor = self.originalTextColor
        return result
    }
    override func resignFirstResponder() -> Bool {
        let result = super.resignFirstResponder()
        updatePlaceHolder()

        return result
    }
}

4

これは私がこの仕事をするために使用しているものです。

@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)
        }
        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 で「Scroll Viewに曖昧なスクロール可能なコンテンツがある」という警告が表示されなくなりました。
  • プレースホルダーの表示/非表示にアニメーションを追加します。

3

Swift 3.2

extension EditProfileVC:UITextViewDelegate{

    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 = "Placeholder"
            textView.textColor = UIColor.lightGray
        }
    }
}

最初に、ユーザーがtextViewDidBeginEditing呼び出しの編集を開始し、テキストグレーの色が何も書かなかったことを確認してから、textview nilとして設定し、ユーザーのテキストメッセージの色を黒に変更します。

ユーザーが編集を終了すると、textViewDidEndEditingが呼び出され、ユーザーがtextviewに何も書き込まないかどうかを確認します。次に、テキストが灰色に設定され、テキスト "PlaceHolder"が設定されます。


3

これがこの問題を解決する私の方法です(Swift 4):

アイデアは、さまざまな色のプレースホルダーを使用でき、プレースホルダーのサイズにサイズ変更でき、delegateその間すべての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) }
}

これは素晴らしいシンプルなソリューションです。
JaredH

2

なぜ人々がこの問題をそれほど複雑にしているのかはわかりません。次に、要求された機能を提供するUITextViewのサブクラスを示します。

- (void)customInit
{
    self.contentMode = UIViewContentModeRedraw;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}

    - (void)textChanged:(NSNotification *)notification
    {
        if (notification.object == self) {
            if(self.textStorage.length != 0 || !self.textStorage.length) {
                [self setNeedsDisplay];
            }
        }
    }


    #pragma mark - Setters

    - (void)setPlaceholderText:(NSString *)placeholderText withFont:(UIFont *)font
    {
        self.placeholderText = placeholderText;
        self.placeholderTextFont = font;

    }



    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
        [[UIColor lightGrayColor] setFill];

        if (self.textStorage.length != 0) {
            return;
        }

        CGRect inset = CGRectInset(rect, 8, 8);//Default rect insets for textView
        NSDictionary *attributes =  @{NSFontAttributeName: self.placeholderTextFont, NSForegroundColorAttributeName: [UIColor grayColor]};
        [self.placeholderText drawInRect:inset withAttributes:attributes];
    }`

参考までに、誰かが私に打ちのめされる前に...これはSwiftに翻訳するのはかなり直接的です。ここでは何も複雑ではありません。
TheCodingArt 2015

2

これは、複数のテキストビューで作業している場合に使用できるソリューションです。

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
    }
}

とても素敵です!
KevinVuD

2

Swift 3.1

この拡張機能は私にとってうまくいきました:https : //github.com/devxoul/UITextView-Placeholder

ここにコードスニペットがあります:

ポッド経由でインストール:

pod 'UITextView+Placeholder', '~> 1.2'

クラスにインポートします

import UITextView_Placeholder

そしてplaceholder、すでに作成したプロパティを追加しますUITextView

textView.placeholder = "Put some detail"

これで終わりです...ここに表示されます(3番目のボックスはUITextViewここに画像の説明を入力してください


2

この投稿のほぼすべての回答とは異なり、にUITextView プレースホルダープロパティがあります。私の理解を超えた理由で、それはIBでのみ公開されています。

<userDefinedRuntimeAttributes>
  <userDefinedRuntimeAttribute type="string" keyPath="placeholder" value="My Placeholder"/>
</userDefinedRuntimeAttributes>

したがって、ストーリーボードを使用していて静的なプレースホルダーで十分な場合は、インスペクターでプロパティを設定するだけです。

このプロパティは、次のようなコードで設定することもできます。

textView.setValue("My Placeholder", forKeyPath: "placeholder")

プロパティ公開されているため、天気が曇り、プライベートAPIを介してアクセスされます。

この方法で送信したことはありません。しかし、私はまもなくこの方法で提出し、それに応じてこの回答を更新します。

更新:

このコードを複数のリリースで出荷しましたが、Appleからの問題はありません。

更新:これはXcode 11.2以前でのみ機能します


スウィフト5であなたがmyTextViewは、プレースホルダ=「あなたの目の色を入力して」書くことができます
user462990

@ user462990このためのドキュメントリンクを提供できますか?これが正確だとは思いません。
Alex Chase

申し訳ありませんが、doxは見つかりませんでしたが、テストは非常に簡単です。例: "alert.addTextField {(textField3)in textField3.placeholder = language.JBLocalize(phrase:" yourName ")}文字列
user462990

4
@ user462990参照しているのではUITextFieldないUITextView ので、質問/回答を注意深く読んでください。
Alex Chase

3
素晴らしい解決策ですが、私にはうまくいきません。どういうわけかそれは常にクラッシュします。使用している展開ターゲット、Swift、およびxCodeのバージョンを指定できますか?
T. Pasichnyk

1

iosには、TextViewに直接プレースホルダーを追加するようなプロパティはありません。ラベルを追加して、textViewの変更を表示/非表示にすることができます。SWIFT 2.0とtextviewdelegateを実装してください

func textViewDidChange(TextView: UITextView)
{

 if  txtShortDescription.text == ""
    {
        self.lblShortDescription.hidden = false
    }
    else
    {
        self.lblShortDescription.hidden = true
    }

}

1

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()
     }

}

制約を使用してプレースホルダーを配置する優れた例ですが、プレースホルダーの理想的な位置は、テキストの最初の文字が配置される場所の真上です。テキストビューのフォントに基づいてその位置を計算すると、適応するため、より適切です。テキストビューに設定されているフォントサイズに設定します。
クリアライト

1

@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()関数がに追加されていextensionます。


オリジナルを改善していただきありがとうございます。私は今週末、wayyyに時間をかけすぎましたが、私が最終的に思いついたEZプレースホルダーエクストリームバリアントをお楽しみいただけると思います:stackoverflow.com/a/41081244/2079103 (私はあなたに、プレースホルダーソリューション)
clearlight '12 / 12/12

1

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かを
明記して

1

評判のせいでコメントは付けられません。@clearlight回答に代理人のニーズをもう1つ追加します。

func textViewDidBeginEditing(_ textView: UITextView) { 
        cell.placeholderLabel.isHidden = !textView.text.isEmpty
}

必要です

textViewDidChange初めて呼ばれないから


1

textviewに使用できるプレースホルダーはありません。ユーザーがtextviewに入力するときにラベルをその上に配置し、ユーザーがすべての値を削除するときに非表示にするか、デフォルト値に設定する必要があります。


1

func setPlaceholder(){
var placeholderLabel = UILabel()
        placeholderLabel.text = "Describe your need..."
        placeholderLabel.font = UIFont.init(name: "Lato-Regular", size: 15.0) ?? UIFont.boldSystemFont(ofSize: 14.0)
        placeholderLabel.sizeToFit()
        descriptionTextView.addSubview(placeholderLabel)
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (descriptionTextView.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !descriptionTextView.text.isEmpty
}



//Delegate Method.

func textViewDidChange(_ textView: UITextView) {
        placeholderLabel.isHidden = !textView.text.isEmpty
    }
	


1

編集が完了したら、プレースホルダーテキストを再表示するためにキューをディスパッチする必要がありました。

func textViewDidBeginEditing(_ textView: UITextView) {

    if textView.text == "Description" {
        textView.text = nil
    }
}

func textViewDidEndEditing(_ textView: UITextView) {

    if textView.text.isEmpty {
        DispatchQueue.main.async {
            textView.text = "Description"
        }
    }
}

この値をユーザーが入力しているものにしたい場合、最後の行” textView.text =” Description”の代わりに何を入力しますか?
ISSの

1

迅速:

あなたの追加TextView @IBOutlet

@IBOutlet weak var txtViewMessage: UITextView!

ではviewWillAppearこの方法は、以下を追加します:

override func viewWillAppear(_ animated: Bool)
{
    super.viewWillAppear(animated)

    txtViewMessage.delegate = self    // Give TextViewMessage delegate Method

    txtViewMessage.text = "Place Holder Name"
    txtViewMessage.textColor = UIColor.lightGray

}

DelegateUsing拡張機能(UITextViewDelegate)を追加してください:

// MARK: - UITextViewDelegate
extension ViewController: UITextViewDelegate
{

    func textViewDidBeginEditing(_ textView: UITextView)
    {

        if !txtViewMessage.text!.isEmpty && txtViewMessage.text! == "Place Holder Name"
        {
            txtViewMessage.text = ""
            txtViewMessage.textColor = UIColor.black
        }
    }

    func textViewDidEndEditing(_ textView: UITextView)
    {

        if txtViewMessage.text.isEmpty
        {
            txtViewMessage.text = "Place Holder Name"
            txtViewMessage.textColor = UIColor.lightGray
        }
    }
}

1

私たちのソリューションは、UITextView textおよびtextColorプロパティをいじるのを避けます。これは、キャラクターカウンターを維持している場合に便利です。

それは簡単です:

1)UITextViewマスターと同じプロパティでストーリーボードにダミーを作成しますUITextView。ダミーテキストにプレースホルダーテキストを割り当てます。

2)2つの上端、左端、右端を揃えます UITextViews.

3)ダミーをマスターの後ろに配置します。

4)textViewDidChange(textView:)マスターのデリゲート機能をオーバーライドし、マスターの文字数が0の場合はダミーを表示します。それ以外の場合は、マスターを表示します。

これは、両方のUITextViews背景が透明であることを前提としています。そうでない場合は、0文字の場合はダミーを上に配置し、0文字以上の場合はダミーを下に押します。また、カーソルが右に追従するように、レスポンダを交換する必要がありますUITextView


1

Swift 4、4.2、および5

[![@IBOutlet var detailTextView: UITextView!

override func viewDidLoad() {
        super.viewDidLoad()
        detailTextView.delegate = self
}

extension ContactUsViewController : UITextViewDelegate {

    public func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.text == "Write your message here..." {
            detailTextView.text = ""
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.86)

        }
        textView.becomeFirstResponder()
    }

    public func textViewDidEndEditing(_ textView: UITextView) {

        if textView.text == "" {
            detailTextView.text = "Write your message here..."
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.30)
        }
        textView.resignFirstResponder()
    }
[![}][1]][1]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.