Placeholder di UITextView

717

Aplikasi saya menggunakan UITextView. Sekarang saya ingin UITextViewmemiliki tempat penampung yang serupa dengan yang Anda dapat tetapkan untuk UITextField.

Bagaimana cara melakukannya?

pengguna142019
sumber
TTTextEditor Three20 (menggunakan UITextField) mendukung teks placeholder serta bertambah tinggi (itu berubah menjadi UITextView).
Josh Benjamin
20
Bagaimana dengan menggunakan kategori UITextView + Placeholder? github.com/devxoul/UITextView-Placeholder
devxoul
2
Saya mendukung solusi @ devxoul karena menggunakan kategori, bukan subkelas. Dan itu juga menciptakan bidang untuk opsi 'placeholder' (teks placeholder & warna teks) di inspektur IB. Ini menggunakan beberapa teknik mengikat. Kode yang luar biasa
samthui7
Jika Anda menggunakan UITextViewsolusinya menjadi sangat berbeda. Berikut adalah beberapa solusi. Floating Placeholder dan Palsu Asli Placeholder
clear

Jawaban:

672

Saya membuat beberapa modifikasi kecil pada solusi bcd untuk memungkinkan inisialisasi dari Xibfile, pembungkus teks, dan mempertahankan warna latar belakang. Semoga itu akan menyelamatkan orang lain dari masalah.

UIPlaceHolderTextView.h:

#import <Foundation/Foundation.h>
IB_DESIGNABLE
@interface UIPlaceHolderTextView : UITextView

@property (nonatomic, retain) IBInspectable NSString *placeholder;
@property (nonatomic, retain) IBInspectable UIColor *placeholderColor;

-(void)textChanged:(NSNotification*)notification;

@end

UIPlaceHolderTextView.m:

#import "UIPlaceHolderTextView.h"

@interface UIPlaceHolderTextView ()

@property (nonatomic, retain) UILabel *placeHolderLabel;

@end

@implementation UIPlaceHolderTextView

CGFloat const UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION = 0.25;

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
#if __has_feature(objc_arc)
#else
    [_placeHolderLabel release]; _placeHolderLabel = nil;
    [_placeholderColor release]; _placeholderColor = nil;
    [_placeholder release]; _placeholder = nil;
    [super dealloc];
#endif
}

- (void)awakeFromNib
{
    [super awakeFromNib];

    // Use Interface Builder User Defined Runtime Attributes to set
    // placeholder and placeholderColor in Interface Builder.
    if (!self.placeholder) {
        [self setPlaceholder:@""];
    }

    if (!self.placeholderColor) {
        [self setPlaceholderColor:[UIColor lightGrayColor]];
    }

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}

- (id)initWithFrame:(CGRect)frame
{
    if( (self = [super initWithFrame:frame]) )
    {
        [self setPlaceholder:@""];
        [self setPlaceholderColor:[UIColor lightGrayColor]];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
    }
    return self;
}

- (void)textChanged:(NSNotification *)notification
{
    if([[self placeholder] length] == 0)
    {
        return;
    }

    [UIView animateWithDuration:UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION animations:^{
    if([[self text] length] == 0)
    {
        [[self viewWithTag:999] setAlpha:1];
    }
    else
    {
        [[self viewWithTag:999] setAlpha:0];
    }
    }];
}

- (void)setText:(NSString *)text {
    [super setText:text];
    [self textChanged:nil];
}

- (void)drawRect:(CGRect)rect
{
    if( [[self placeholder] length] > 0 )
    {
        if (_placeHolderLabel == nil )
        {
            _placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
            _placeHolderLabel.lineBreakMode = NSLineBreakByWordWrapping;
            _placeHolderLabel.numberOfLines = 0;
            _placeHolderLabel.font = self.font;
            _placeHolderLabel.backgroundColor = [UIColor clearColor];
            _placeHolderLabel.textColor = self.placeholderColor;
            _placeHolderLabel.alpha = 0;
            _placeHolderLabel.tag = 999;
            [self addSubview:_placeHolderLabel];
        }

        _placeHolderLabel.text = self.placeholder;
        [_placeHolderLabel sizeToFit];
        [self sendSubviewToBack:_placeHolderLabel];
    }

    if( [[self text] length] == 0 && [[self placeholder] length] > 0 )
    {
        [[self viewWithTag:999] setAlpha:1];
    }

    [super drawRect:rect];
}

@end
Jason George
sumber
2
dalam beberapa kasus (kompatibilitas iOS 5) diperlukan untuk menimpa tempel: - (kosong) tempel: (id) pengirim {[super paste: pengirim]; [self textChanged: nil]; }
Martin Ullrich
3
Barang bagus! Pengingat tentang praktik terbaik untuk NSString (atau kelas apa pun yang memiliki setara NSMutableXXX), properti harus "menyalin" dan tidak "mempertahankan".
Oli
2
Bagaimana Anda membuat instantiate kode ini? Saya tidak melihat teks placeholder dan tidak ada yang jelas saat saya mulai mengetik.
user798719
40
Ini adalah implementasi yang ditulis dengan sangat, sangat buruk. Berikut ini adalah versi yang jauh lebih bersih yang juga mengawasi perubahan dikte: github.com/cbowns/MPTextView
cbowns
10
Jangan memodifikasi hierarki tampilan di drawRect.
Karmeye
634

Cara mudah, cukup buat teks placeholder UITextViewdengan menggunakan UITextViewDelegatemetode berikut :

- (void)textViewDidBeginEditing:(UITextView *)textView
{
    if ([textView.text isEqualToString:@"placeholder text here..."]) {
         textView.text = @"";
         textView.textColor = [UIColor blackColor]; //optional
    }
    [textView becomeFirstResponder];
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
    if ([textView.text isEqualToString:@""]) {
        textView.text = @"placeholder text here...";
        textView.textColor = [UIColor lightGrayColor]; //optional
    }
    [textView resignFirstResponder];
}

hanya ingat untuk mengatur myUITextViewdengan teks yang tepat pada kreasi misalnya

UITextView *myUITextView = [[UITextView alloc] init];
myUITextView.delegate = self;
myUITextView.text = @"placeholder text here...";
myUITextView.textColor = [UIColor lightGrayColor]; //optional

dan membuat kelas induk UITextViewDelegatesebelum memasukkan metode ini misalnya

@interface MyClass () <UITextViewDelegate>
@end

Kode untuk Swift 3.1

func textViewDidBeginEditing(_ textView: UITextView) 
{
    if (textView.text == "placeholder text here..." && textView.textColor == .lightGray)
    {
        textView.text = ""
        textView.textColor = .black
    }
    textView.becomeFirstResponder() //Optional
}

func textViewDidEndEditing(_ textView: UITextView)
{
    if (textView.text == "")
    {
        textView.text = "placeholder text here..."
        textView.textColor = .lightGray
    }
    textView.resignFirstResponder()
}

hanya ingat untuk mengatur myUITextViewdengan teks yang tepat pada kreasi misalnya

 let myUITextView = UITextView.init()
 myUITextView.delegate = self
 myUITextView.text = "placeholder text here..."
 myUITextView.textColor = .lightGray

dan membuat kelas induk UITextViewDelegatesebelum memasukkan metode ini misalnya

class MyClass: UITextViewDelegate
{

}
CmKndy
sumber
1
Ini luar biasa (saya suka sederhana) untuk 1 layar dengan 1 UITextView. Alasan untuk solusi yang lebih rumit adalah bahwa jika Anda memiliki aplikasi yang lebih besar dengan layar BANYAK dan BANYAK UITextViews, Anda tidak ingin melakukan ini berulang kali. Anda mungkin ingin subkelas UITextView agar sesuai dengan kebutuhan Anda dan kemudian menggunakannya.
ghostatron
42
Jika seseorang mengetik "teks placeholder di sini ..." di kotak teks itu juga berperilaku seperti teks placeholder. Juga, selama pengiriman Anda harus memeriksa semua kriteria tersebut.
Anindya Sengupta
7
Teks placeholder seharusnya menunjukkan bahkan ketika bidang menjadi responden, dan metode ini tidak akan berfungsi untuk ini.
phatmann
17
@ jklp Saya berpendapat bahwa cara "over-engineered" lebih bersih dan lebih dapat digunakan kembali ... dan sepertinya tidak merusak textatribut textview yang agak bagus .. Di mana metode ini memodifikasinya
Cameron Askew
2
mengapa panggilan untuk menjadiFirstResponder dan mengundurkan diriFirstResponder dalam metode delegasi?
Adam Johns
119

Saya tidak terlalu senang dengan solusi yang diposting karena mereka agak berat. Menambahkan tampilan ke tampilan tidak terlalu ideal (terutama di drawRect:). Mereka berdua mengalami kebocoran, yang juga tidak dapat diterima.

Inilah solusi saya: SAMTextView

SAMTextView.h

//
//  SAMTextView.h
//  SAMTextView
//
//  Created by Sam Soffes on 8/18/10.
//  Copyright 2010-2013 Sam Soffes. All rights reserved.
//

#import <UIKit/UIKit.h>

/**
 UITextView subclass that adds placeholder support like UITextField has.
 */
@interface SAMTextView : UITextView

/**
 The string that is displayed when there is no other text in the text view.

 The default value is `nil`.
 */
@property (nonatomic, strong) NSString *placeholder;

/**
 The color of the placeholder.

 The default is `[UIColor lightGrayColor]`.
 */
@property (nonatomic, strong) UIColor *placeholderTextColor;

/**
 Returns the drawing rectangle for the text views’s placeholder text.

 @param bounds The bounding rectangle of the receiver.
 @return The computed drawing rectangle for the placeholder text.
 */
- (CGRect)placeholderRectForBounds:(CGRect)bounds;

@end

SAMTextView.m

//
//  SAMTextView.m
//  SAMTextView
//
//  Created by Sam Soffes on 8/18/10.
//  Copyright 2010-2013 Sam Soffes. All rights reserved.
//

#import "SAMTextView.h"

@implementation SAMTextView

#pragma mark - Accessors

@synthesize placeholder = _placeholder;
@synthesize placeholderTextColor = _placeholderTextColor;

- (void)setText:(NSString *)string {
  [super setText:string];
  [self setNeedsDisplay];
}


- (void)insertText:(NSString *)string {
  [super insertText:string];
  [self setNeedsDisplay];
}


- (void)setAttributedText:(NSAttributedString *)attributedText {
  [super setAttributedText:attributedText];
  [self setNeedsDisplay];
}


- (void)setPlaceholder:(NSString *)string {
  if ([string isEqual:_placeholder]) {
    return;
  }

  _placeholder = string;
  [self setNeedsDisplay];
}


- (void)setContentInset:(UIEdgeInsets)contentInset {
  [super setContentInset:contentInset];
  [self setNeedsDisplay];
}


- (void)setFont:(UIFont *)font {
  [super setFont:font];
  [self setNeedsDisplay];
}


- (void)setTextAlignment:(NSTextAlignment)textAlignment {
  [super setTextAlignment:textAlignment];
  [self setNeedsDisplay];
}


#pragma mark - NSObject

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:self];
}


#pragma mark - UIView

- (id)initWithCoder:(NSCoder *)aDecoder {
  if ((self = [super initWithCoder:aDecoder])) {
    [self initialize];
  }
  return self;
}


- (id)initWithFrame:(CGRect)frame {
  if ((self = [super initWithFrame:frame])) {
    [self initialize];
  }
  return self;
}


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

  if (self.text.length == 0 && self.placeholder) {
    rect = [self placeholderRectForBounds:self.bounds];

    UIFont *font = self.font ? self.font : self.typingAttributes[NSFontAttributeName];

    // Draw the text
    [self.placeholderTextColor set];
    [self.placeholder drawInRect:rect withFont:font lineBreakMode:NSLineBreakByTruncatingTail alignment:self.textAlignment];
  }
}


#pragma mark - Placeholder

- (CGRect)placeholderRectForBounds:(CGRect)bounds {
  // Inset the rect
  CGRect rect = UIEdgeInsetsInsetRect(bounds, self.contentInset);

  if (self.typingAttributes) {
    NSParagraphStyle *style = self.typingAttributes[NSParagraphStyleAttributeName];
    if (style) {
      rect.origin.x += style.headIndent;
      rect.origin.y += style.firstLineHeadIndent;
    }
  }

  return rect;
}


#pragma mark - Private

- (void)initialize {
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:self];

  self.placeholderTextColor = [UIColor colorWithWhite:0.702f alpha:1.0f];
}


- (void)textChanged:(NSNotification *)notification {
  [self setNeedsDisplay];
}

@end

Ini jauh lebih sederhana daripada yang lain, karena tidak menggunakan subview (atau memiliki kebocoran). Jangan ragu untuk menggunakannya.

Pembaruan 11/10/11: Sekarang telah didokumentasikan dan mendukung penggunaan di Interface Builder.

Pembaruan 11/24/13: Arahkan ke repo baru.

Sam Soffes
sumber
Saya suka solusi Anda, dan saya menambahkan penggantian setTextuntuk juga memperbarui placeholder ketika mengubah properti teks secara terprogram: - (void) setText: (NSString *) string {[super setText: string]; [self _updateShouldDrawPlaceholder]; }
olegueret
1
Saya juga menyukai solusi Anda, tetapi Anda melewatkan metode awakefromnib sehingga metode init Anda tidak akan selalu dipanggil. Saya mengambilnya dari salah satu yang lain di sini.
toxaq
Catatan - angka ajaib akan bervariasi tergantung pada ukuran font. Penentuan posisi yang tepat dapat dihitung dari font, tetapi mungkin tidak layak untuk implementasi ini. Penempatan placeholder yang benar harus 2px di sebelah kanan posisi kursor saat tidak ada teks.
memmons
Untuk mengatasi pemuatan dari nib: Anda mungkin ingin menambahkan - (id) initWithCoder: (NSCoder *) aDecoder; initializer untuk menemani yang sudah ada.
Joris Kluivers
Ini manis. The notificationargumen salah eja dalam metode terakhir, meskipun, dan itu perubahan terlalu kecil untuk mengirimkan sebagai edit.
Phil Calvin
53

Saya menemukan diri saya cara yang sangat mudah untuk meniru place-holder

  1. di NIB atau kode atur textView Anda TextColor ke lightGrayColor (sebagian besar waktu)
  2. pastikan bahwa delegasi textView Anda ditautkan ke pemilik file dan terapkan UITextViewDelegate dalam file header Anda
  3. atur teks default tampilan teks Anda ke (contoh: "Foobar placeholder")
  4. implementasikan: (BOOL) textViewShouldBeginEditing: (UITextView *) textView

Edit:

Pernyataan if yang diubah untuk membandingkan tag dan bukan teks. Jika pengguna menghapus teks mereka, mungkin juga secara tidak sengaja menghapus sebagian tempat @"Foobar placeholder"penampung. Ini berarti jika pengguna memasukkan kembali textView dengan metode delegasi berikut -(BOOL) textViewShouldBeginEditing:(UITextView *) textView,, itu tidak akan berfungsi seperti yang diharapkan. Saya mencoba membandingkan dengan warna teks dalam pernyataan if tetapi menemukan bahwa warna abu-abu muda yang diatur dalam pembuat antarmuka tidak sama dengan warna abu-abu muda yang diatur dalam kode dengan[UIColor lightGreyColor]

- (BOOL) textViewShouldBeginEditing:(UITextView *)textView
{
    if(textView.tag == 0) {
        textView.text = @"";
        textView.textColor = [UIColor blackColor];
        textView.tag = 1;
    }
    return YES;
}

Dimungkinkan juga untuk mereset teks placeholder ketika keyboard kembali dan [textView length] == 0

EDIT:

Untuk memperjelas bagian terakhir - inilah cara Anda dapat mengatur teks placeholder kembali:

- (void)textViewDidChange:(UITextView *)textView
{
   if([textView.text length] == 0)
   {
       textView.text = @"Foobar placeholder";
       textView.textColor = [UIColor lightGrayColor];
       textView.tag = 0;
   }
}
vdevos
sumber
12
Saya sangat menyukai pendekatan ini! Satu-satunya hal yang akan saya lakukan untuk mengedit di atas adalah memindahkan implementasi dari metode textViewDidChange: dan ke metode textViewDidEndEditing:, sehingga teks placeholder hanya kembali setelah Anda selesai bekerja dengan objek.
horseshoe7
52

Yang dapat Anda lakukan adalah mengatur tampilan teks dengan beberapa nilai awal di textproperti, dan mengubah textColorke [UIColor grayColor]atau sesuatu yang serupa. Kemudian, setiap kali tampilan teks menjadi dapat diedit, hapus teks dan sajikan kursor, dan jika bidang teks pernah kosong lagi, kembalikan teks placeholder Anda. Ubah warnanya [UIColor blackColor]sesuai kebutuhan.

Ini tidak persis sama dengan fungsionalitas placeholder di UITextField, tapi dekat.

Tim
sumber
9
Saya selalu menggunakan lightGrayColor , yang tampaknya cocok dengan warna teks placeholder.
Bill
Saya baru saja membaca ini sekarang, tetapi saya ingin menambahkan bahwa mengatur ulang warna menjadi hitam dan mengatur ulang properti teks di textViewShouldBeginEditing: (UITextView *) textView bekerja dengan sangat baik. Ini adalah solusi yang sangat bagus dan cepat dibandingkan dengan solusi di bawah ini (tapi masih solusi elegan di bawah ini, subclassing uitextview. Jauh lebih modular).
Enrico Susatyo
3
Benar, tetapi itu tidak meniru perilaku UITextField, yang hanya menggantikan teks placeholder ketika pengguna mengetik sesuatu, bukan saat pengeditan dimulai, dan yang menambahkan placeholder kembali lagi saat tampilan kosong, bukan saat pengeditan benar-benar selesai.
Ash
47

Anda dapat mengatur label pada UITextViewoleh

[UITextView addSubView:lblPlaceHoldaer];

dan sembunyikan di TextViewdidChangemetode.

Ini adalah cara sederhana & mudah.

Mohammed Yakub Moriswala
sumber
45

Jika seseorang membutuhkan Solusi untuk Swift:

Tambahkan UITextViewDelegate ke kelas Anda

var placeHolderText = "Placeholder Text..."

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

func textViewShouldBeginEditing(textView: UITextView) -> Bool {

    self.textView.textColor = .black

    if(self.textView.text == placeHolderText) {
        self.textView.text = ""
    }

    return true
}

func textViewDidEndEditing(textView: UITextView) {
    if(textView.text == "") {
        self.textView.text = placeHolderText
        self.textView.textColor = .lightGray
    }
}

override func viewWillAppear(animated: Bool) {

    if(currentQuestion.answerDisplayValue == "") {
        self.textView.text = placeHolderText
        self.textView.textColor = .lightGray
    } else {
        self.textView.text = "xxx" // load default text / or stored 
        self.textView.textColor = .black
    }
}
derdida
sumber
ini ok tapi tidak cukup bagus. jika pengguna mengetik "Placeholder Text ..." (jelas tepi case), itu akan merusak logika Anda
Lucas Chwe
45

Sederhana Swift 3 solusi

Tambahkan UITextViewDelegateke kelas Anda

Set yourTextView.delegate = self

Buat placeholderLabeldan posisikan di dalamyourTextView

Sekarang hanya hidupkan placeholderLabel.alphapada textViewDidChange:

  func textViewDidChange(_ textView: UITextView) {
    let newAlpha: CGFloat = textView.text.isEmpty ? 1 : 0
    if placeholderLabel.alpha != newAlpha {
      UIView.animate(withDuration: 0.3) {
        self.placeholderLabel.alpha = newAlpha
      }
    }
  }

Anda mungkin harus bermain dengan placeholderLabelposisi untuk mengaturnya dengan benar, tetapi itu seharusnya tidak terlalu sulit

budidino
sumber
1
Jawaban yang bagus, solusi sederhana. Saya menambahkan peningkatan kecil untuk menghidupkan hanya ketika alpha harus berubah: let alpha = CGFloat(textView.text.isEmpty ? 1.0 : 0.0) if alpha != lblPlaceholder.alpha { UIView.animate(withDuration: 0.3) { self.lblPlaceholder.alpha = alpha } }
Luciano Sclovsky
24

Saya memperluas jawaban KmKndy, sehingga placeholder tetap terlihat sampai pengguna mulai mengedit, UITextViewbukan hanya mengetuknya. Ini mencerminkan fungsi di aplikasi Twitter dan Facebook. Solusi saya tidak mengharuskan Anda untuk subkelas dan berfungsi jika pengguna mengetik secara langsung atau menempelkan teks!

Contoh Placeholder Aplikasi Twitter

- (void)textViewDidChangeSelection:(UITextView *)textView{
    if ([textView.text isEqualToString:@"What's happening?"] && [textView.textColor isEqual:[UIColor lightGrayColor]])[textView setSelectedRange:NSMakeRange(0, 0)];

}

- (void)textViewDidBeginEditing:(UITextView *)textView{

    [textView setSelectedRange:NSMakeRange(0, 0)];
}

- (void)textViewDidChange:(UITextView *)textView
{
    if (textView.text.length != 0 && [[textView.text substringFromIndex:1] isEqualToString:@"What's happening?"] && [textView.textColor isEqual:[UIColor lightGrayColor]]){
        textView.text = [textView.text substringToIndex:1];
        textView.textColor = [UIColor blackColor]; //optional

    }
    else if(textView.text.length == 0){
        textView.text = @"What's happening?";
        textView.textColor = [UIColor lightGrayColor];
        [textView setSelectedRange:NSMakeRange(0, 0)];
    }
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
    if ([textView.text isEqualToString:@""]) {
        textView.text = @"What's happening?";
        textView.textColor = [UIColor lightGrayColor]; //optional
    }
    [textView resignFirstResponder];
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
    if (textView.text.length > 1 && [textView.text isEqualToString:@"What's happening?"]) {
         textView.text = @"";
         textView.textColor = [UIColor blackColor];
    }

    return YES;
}

hanya ingat untuk mengatur myUITextView dengan teks yang tepat pada kreasi misalnya

UITextView *myUITextView = [[UITextView alloc] init];
myUITextView.delegate = self;
myUITextView.text = @"What's happening?";
myUITextView.textColor = [UIColor lightGrayColor]; //optional

dan buat kelas induk sebagai delegasi UITextView sebelum memasukkan metode ini, mis

@interface MyClass () <UITextViewDelegate>
@end
Matt
sumber
20

Saya sarankan untuk digunakan SZTextView.

https://github.com/glaszig/SZTextView

Tambahkan default Anda UITextViewdari storyboarddan kemudian ubah kelas kustom menjadi SZTextViewseperti di bawah ini 👇👇👇👇

masukkan deskripsi gambar di sini

Maka Anda akan melihat dua opsi baru di Attribute Inspector👇👇👇👇

masukkan deskripsi gambar di sini

Vaibhav Saran
sumber
20

Di bawah ini adalah port Swift dari "SAMTextView" kode ObjC yang diposting sebagai salah satu dari segelintir balasan pertama untuk pertanyaan tersebut. Saya mengujinya di iOS 8. Saya men-tweak beberapa hal, termasuk batas offset untuk penempatan teks placeholder, karena aslinya terlalu tinggi dan terlalu jauh ke kanan (digunakan saran di salah satu komentar untuk posting itu).

Saya tahu ada banyak solusi sederhana, tapi saya suka pendekatan subclassing UITextView karena dapat digunakan kembali dan saya tidak perlu mengacaukan kelas yang menggunakannya dengan mekanisme.

Swift 2.2:

import UIKit

class PlaceholderTextView: UITextView {

    @IBInspectable var placeholderColor: UIColor = UIColor.lightGrayColor()
    @IBInspectable var placeholderText: String = ""

    override var font: UIFont? {
        didSet {
            setNeedsDisplay()
        }
    }

    override var contentInset: UIEdgeInsets {
        didSet {
            setNeedsDisplay()
        }
    }

    override var textAlignment: NSTextAlignment {
        didSet {
            setNeedsDisplay()
        }
    }

    override var text: String? {
        didSet {
            setNeedsDisplay()
        }
    }

    override var attributedText: NSAttributedString? {
        didSet {
            setNeedsDisplay()
        }
    }

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

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
    }

    private func setUp() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PlaceholderTextView.textChanged(_:)),
                                                         name: UITextViewTextDidChangeNotification, object: self)
    }

    func textChanged(notification: NSNotification) {
        setNeedsDisplay()
    }

    func placeholderRectForBounds(bounds: CGRect) -> CGRect {
        var x = contentInset.left + 4.0
        var y = contentInset.top  + 9.0
        let w = frame.size.width - contentInset.left - contentInset.right - 16.0
        let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0

        if let style = self.typingAttributes[NSParagraphStyleAttributeName] as? NSParagraphStyle {
            x += style.headIndent
            y += style.firstLineHeadIndent
        }
        return CGRect(x: x, y: y, width: w, height: h)
    }

    override func drawRect(rect: CGRect) {
        if text!.isEmpty && !placeholderText.isEmpty {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.alignment = textAlignment
            let attributes: [ String: AnyObject ] = [
                NSFontAttributeName : font!,
                NSForegroundColorAttributeName : placeholderColor,
                NSParagraphStyleAttributeName  : paragraphStyle]

            placeholderText.drawInRect(placeholderRectForBounds(bounds), withAttributes: attributes)
        }
        super.drawRect(rect)
    }
}

Swift 4.2:

import UIKit

class PlaceholderTextView: UITextView {

    @IBInspectable var placeholderColor: UIColor = UIColor.lightGray
    @IBInspectable var placeholderText: String = ""

    override var font: UIFont? {
        didSet {
            setNeedsDisplay()
        }
    }

    override var contentInset: UIEdgeInsets {
        didSet {
            setNeedsDisplay()
        }
    }

    override var textAlignment: NSTextAlignment {
        didSet {
            setNeedsDisplay()
        }
    }

    override var text: String? {
        didSet {
            setNeedsDisplay()
        }
    }

    override var attributedText: NSAttributedString? {
        didSet {
            setNeedsDisplay()
        }
    }

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

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
    }

    private func setUp() {
        NotificationCenter.default.addObserver(self,
         selector: #selector(self.textChanged(notification:)),
         name: Notification.Name("UITextViewTextDidChangeNotification"),
         object: nil)
    }

    @objc func textChanged(notification: NSNotification) {
        setNeedsDisplay()
    }

    func placeholderRectForBounds(bounds: CGRect) -> CGRect {
        var x = contentInset.left + 4.0
        var y = contentInset.top  + 9.0
        let w = frame.size.width - contentInset.left - contentInset.right - 16.0
        let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0

        if let style = self.typingAttributes[NSAttributedString.Key.paragraphStyle] as? NSParagraphStyle {
            x += style.headIndent
            y += style.firstLineHeadIndent
        }
        return CGRect(x: x, y: y, width: w, height: h)
    }

    override func draw(_ rect: CGRect) {
        if text!.isEmpty && !placeholderText.isEmpty {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.alignment = textAlignment
            let attributes: [NSAttributedString.Key: Any] = [
            NSAttributedString.Key(rawValue: NSAttributedString.Key.font.rawValue) : font!,
            NSAttributedString.Key(rawValue: NSAttributedString.Key.foregroundColor.rawValue) : placeholderColor,
            NSAttributedString.Key(rawValue: NSAttributedString.Key.paragraphStyle.rawValue)  : paragraphStyle]

            placeholderText.draw(in: placeholderRectForBounds(bounds: bounds), withAttributes: attributes)
        }
        super.draw(rect)
    }
}
clearlight
sumber
Terima kasih untuk melakukan versi cepat, dapatkah Anda menjelaskan apa gunanya memiliki metode awakeFromNib yang hanya memanggil super?
Pierre
Ini menetapkan placeholder, tetapi tidak diperbarui setelah Anda mulai mengetik.
David
Nevermind, saya meletakkan panggilan notifikasi di awakeFromNib dan berfungsi sekarang.
David
12

beginilah cara saya melakukannya:

UITextView2.h

#import <UIKit/UIKit.h>

@interface UITextView2 : UITextView <UITextViewDelegate> {
 NSString *placeholder;
 UIColor *placeholderColor;
}

@property(nonatomic, retain) NSString *placeholder;
@property(nonatomic, retain) UIColor *placeholderColor;

-(void)textChanged:(NSNotification*)notif;

@end

UITextView2.m

@implementation UITextView2

@synthesize placeholder, placeholderColor;

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self setPlaceholder:@""];
        [self setPlaceholderColor:[UIColor lightGrayColor]];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
    }
    return self;
}

-(void)textChanged:(NSNotification*)notif {
    if ([[self placeholder] length]==0)
        return;
    if ([[self text] length]==0) {
        [[self viewWithTag:999] setAlpha:1];
    } else {
        [[self viewWithTag:999] setAlpha:0];
    }

}

- (void)drawRect:(CGRect)rect {
    if ([[self placeholder] length]>0) {
        UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(8, 8, 0, 0)];
        [l setFont:self.font];
        [l setTextColor:self.placeholderColor];
        [l setText:self.placeholder];
        [l setAlpha:0];
        [l setTag:999];
        [self addSubview:l];
        [l sizeToFit];
        [self sendSubviewToBack:l];
        [l release];
    }
    if ([[self text] length]==0 && [[self placeholder] length]>0) {
        [[self viewWithTag:999] setAlpha:1];
    }
    [super drawRect:rect];
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}


@end
bcd
sumber
12

Berikut adalah solusi yang lebih mudah yang berperilaku persis seperti placeholder UITextField tetapi tidak memerlukan menggambar tampilan khusus, atau mengundurkan diri dari responden pertama.

- (void) textViewDidChange:(UITextView *)textView{

    if (textView.text.length == 0){
        textView.textColor = [UIColor lightGrayColor];
        textView.text = placeholderText;
        [textView setSelectedRange:NSMakeRange(0, 0)];
        isPlaceholder = YES;

    } else if (isPlaceholder && ![textView.text isEqualToString:placeholderText]) {
        textView.text = [textView.text substringToIndex:1];
        textView.textColor = [UIColor blackColor];
        isPlaceholder = NO;
    }

}

(cek kedua di pernyataan lain apakah untuk kasus di mana tidak ada yang dimasukkan dan pengguna menekan backspace)

Atur saja kelas Anda sebagai UITextViewDelegate. Di viewDidLoad Anda harus menginisialisasi suka

- (void) viewDidLoad{
    // initialize placeholder text
    placeholderText = @"some placeholder";
    isPlaceholder = YES;
    self.someTextView.text = placeholderText;
    self.someTextView.textColor = [UIColor lightGrayColor];
    [self.someTextView setSelectedRange:NSMakeRange(0, 0)];

    // assign UITextViewDelegate
    self.someTextView.delegate = self;
}
aning
sumber
2
Masalahnya adalah bahwa jika pengguna mengetuk suatu tempat di tengah tanda "teks placeholder" tetap ada.
Alex Sorokoletov
10

Hai, Anda dapat menggunakan IQTextView yang tersedia di IQKeyboard Manager. Mudah digunakan dan diintegrasikan, cukup atur kelas tampilan teks Anda ke IQTextView dan Anda dapat menggunakan propertinya untuk mengatur label tempat penampung dengan warna yang Anda inginkan. Anda dapat mengunduh perpustakaan dari IQKeyboardManager

atau Anda dapat menginstalnya dari cocoapods.

Amit Shelgaonkar
sumber
IQKeyboardManager sangat berguna dan tanpa kode. Jawaban terbaik untuk saya!
NSDeveloper
1
Sebenarnya saya memilih dan meninggalkan komentar untuk alasan itu. Saya tidak tahu IQTextView tersedia di IQKeyboardManager sebelumnya.
NSDeveloper
Saya punya masalah dengan delegasi. Saya menghapus dari kelas delegasi menimpa dan UITextViewDelegatebekerja dengan baik
TheoK
jawaban yang kurang
diperhatikan
10

Maaf menambahkan jawaban lain, Tapi saya baru saja menarik sesuatu seperti ini dan ini menciptakan placeholder jenis UITextField terdekat.

Semoga ini bisa membantu seseorang.

-(void)textViewDidChange:(UITextView *)textView{
    if(textView.textColor == [UIColor lightGrayColor]){
        textView.textColor  = [UIColor blackColor]; // look at the comment section in this answer
        textView.text       = [textView.text substringToIndex: 0];// look at the comment section in this answer
    }else if(textView.text.length == 0){
        textView.text       = @"This is some placeholder text.";
        textView.textColor  = [UIColor lightGrayColor];
        textView.selectedRange = NSMakeRange(0, 0);
    }
}

-(void)textViewDidChangeSelection:(UITextView *)textView{
    if(textView.textColor == [UIColor lightGrayColor] && (textView.selectedRange.location != 0 || textView.selectedRange.length != 0)){
        textView.selectedRange = NSMakeRange(0, 0);
    }
}
Shai Mishali
sumber
1
Saya harus mengubah urutan perintah di pernyataan if pertama. Jika if(textView.textColor == [UIColor lightGrayColor]){ textView.textColor = [UIColor blackColor]; textView.text = [textView.text substringToIndex: 1]; tidak, karakter pertama yang dimasukkan dalam tampilan teks ditempatkan di akhir teks
Flexicoder
7

Cara mudah untuk menggunakan ini dalam beberapa baris kode:

Ambil satu label hingga UITextView di .nib menghubungkan label ini ke kode Anda, Setelah itu.

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{

    if (range.location>0 || text.length!=0) {
        placeholderLabel1.hidden = YES;
    }else{
        placeholderLabel1.hidden = NO;
    }
    return YES;
}
SachinVsSachin
sumber
7

Saya telah memodifikasi implementasi Sam Soffes untuk bekerja dengan iOS7:

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

    if (_shouldDrawPlaceholder)
    {
        UIEdgeInsets insets = self.textContainerInset;        
        CGRect placeholderRect = CGRectMake(
                insets.left + self.textContainer.lineFragmentPadding,
                insets.top,
                self.frame.size.width - insets.left - insets.right,
                self.frame.size.height - insets.top - insets.bottom);

        [_placeholderText drawWithRect:placeholderRect
                           options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine
                        attributes:self.placeholderAttributes
                           context:nil];
    }
}

- (NSDictionary *)placeholderAttributes
{
    if (_placeholderAttributes == nil)
    {
        _placeholderAttributes = @
        {
            NSFontAttributeName : self.font,
            NSForegroundColorAttributeName : self.placeholderColor
        };
    }

    return _placeholderAttributes;
}

Ingatlah untuk mengatur _placeholderAttribues = nilmetode yang dapat mengubah font dan hal lain yang mungkin memengaruhi mereka. Anda mungkin juga ingin melewatkan pembuatan kamus atribut "malas" jika itu tidak mengganggu Anda.

EDIT:

Ingatlah untuk memanggil setNeedsDisplay dalam versi setBounds yang diganti jika Anda menyukai placeholder agar terlihat bagus setelah animasi autolayout dan sejenisnya.

Nailer
sumber
Saya pikir Anda harus menambahkan insets.left ke parameter x offset.
Karmeye
bukankah setFrame bukan setBounds?
JakubKnejzlik
Nggak! tampaknya setFrame tidak dipanggil selama animasi tata letak.
Nailer
6

Anda juga bisa membuat TextViewWithPlaceholder kelas baru sebagai subclass dari UITextView.

(Kode ini agak kasar - tapi saya pikir ini berada di jalur yang benar.)

@interface TextViewWithPlaceholder : UITextView
{

    NSString *placeholderText;  // make a property
    UIColor *placeholderColor;  // make a property
    UIColor *normalTextColor;   // cache text color here whenever you switch to the placeholderColor
}

- (void) setTextColor: (UIColor*) color
{
   normalTextColor = color;
   [super setTextColor: color];
}

- (void) updateForTextChange
{
    if ([self.text length] == 0)
    { 
        normalTextColor = self.textColor;
        self.textColor = placeholderColor;
        self.text = placeholderText;
    }
    else
    {
        self.textColor = normalTextColor;
    }

}

Di delegasi Anda, tambahkan ini:

- (void)textViewDidChange:(UITextView *)textView
{
    if ([textView respondsToSelector: @selector(updateForTextChange)])
    {
        [textView updateForTextChange];
    }

}
Amagrammer
sumber
1
Untuk mendapatkan perilaku yang tepat, Anda harus mengecat placeholder Anda sendiri dengan mengesampingkan drawRect: (draw placeholder hanya jika! [Self isFirstResponder] && [panjang [self text]] == 0, dan memanggil setNeedsDisplay inside menjadiFirstResponder dan mengundurkan diriFirstResponder
rpetrich
6

Saya membuat versi saya sendiri dari subclass dari 'UITextView'. Saya menyukai gagasan Sam Soffes untuk menggunakan notifikasi, tetapi saya tidak menyukai drawRect: ditimpa. Tampak berlebihan bagi saya. Saya pikir saya membuat implementasi yang sangat bersih.

Anda dapat melihat subkelas saya di sini . Proyek demo juga disertakan.

gcamp
sumber
6

Utas ini telah memiliki banyak jawaban, tetapi inilah versi yang saya sukai.

Itu memperluasUITextView kelas yang sudah ada sehingga mudah digunakan kembali, dan itu tidak mencegat peristiwa seperti textViewDidChange(yang dapat merusak kode pengguna, jika mereka sudah mencegat acara ini di tempat lain).

Menggunakan kode saya (diperlihatkan di bawah), Anda dapat dengan mudah menambahkan placeholder ke salah satu dari Anda UITextViewsseperti ini:

self.textViewComments.placeholder = @"(Enter some comments here.)";

Saat Anda menetapkan nilai tempat penampung baru ini, itu menambahkan nilai diam-diam UILabeldi atas Anda UITextView, lalu sembunyikan / perlihatkan:

masukkan deskripsi gambar di sini

Oke, untuk melakukan perubahan ini, tambahkan file "UITextViewHelper.h" yang berisi kode ini:

//  UITextViewHelper.h
//  Created by Michael Gledhill on 13/02/15.

#import <Foundation/Foundation.h>

@interface UITextView (UITextViewHelper)

@property (nonatomic, strong) NSString* placeholder;
@property (nonatomic, strong) UILabel* placeholderLabel;
@property (nonatomic, strong) NSString* textValue;

-(void)checkIfNeedToDisplayPlaceholder;

@end

... dan file UITextViewHelper.m yang berisi ini:

//  UITextViewHelper.m
//  Created by Michael Gledhill on 13/02/15.
//
//  This UITextView category allows us to easily display a PlaceHolder string in our UITextView.
//  The downside is that, your code needs to set the "textValue" rather than the "text" value to safely set the UITextView's text.
//
#import "UITextViewHelper.h"
#import <objc/runtime.h>

@implementation UITextView (UITextViewHelper)

#define UI_PLACEHOLDER_TEXT_COLOR [UIColor colorWithRed:170.0/255.0 green:170.0/255.0 blue:170.0/255.0 alpha:1.0]

@dynamic placeholder;
@dynamic placeholderLabel;
@dynamic textValue;

-(void)setTextValue:(NSString *)textValue
{
    //  Change the text of our UITextView, and check whether we need to display the placeholder.
    self.text = textValue;
    [self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)textValue
{
    return self.text;
}

-(void)checkIfNeedToDisplayPlaceholder
{
    //  If our UITextView is empty, display our Placeholder label (if we have one)
    if (self.placeholderLabel == nil)
        return;

    self.placeholderLabel.hidden = (![self.text isEqualToString:@""]);
}

-(void)onTap
{
    //  When the user taps in our UITextView, we'll see if we need to remove the placeholder text.
    [self checkIfNeedToDisplayPlaceholder];

    //  Make the onscreen keyboard appear.
    [self becomeFirstResponder];
}

-(void)keyPressed:(NSNotification*)notification
{
    //  The user has just typed a character in our UITextView (or pressed the delete key).
    //  Do we need to display our Placeholder label ?
   [self checkIfNeedToDisplayPlaceholder];
}

#pragma mark - Add a "placeHolder" string to the UITextView class

NSString const *kKeyPlaceHolder = @"kKeyPlaceHolder";
-(void)setPlaceholder:(NSString *)_placeholder
{
    //  Sets our "placeholder" text string, creates a new UILabel to contain it, and modifies our UITextView to cope with
    //  showing/hiding the UILabel when needed.
    objc_setAssociatedObject(self, &kKeyPlaceHolder, (id)_placeholder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    self.placeholderLabel = [[UILabel alloc] initWithFrame:self.frame];
    self.placeholderLabel.numberOfLines = 1;
    self.placeholderLabel.text = _placeholder;
    self.placeholderLabel.textColor = UI_PLACEHOLDER_TEXT_COLOR;
    self.placeholderLabel.backgroundColor = [UIColor clearColor];
    self.placeholderLabel.userInteractionEnabled = true;
    self.placeholderLabel.font = self.font;
    [self addSubview:self.placeholderLabel];

    [self.placeholderLabel sizeToFit];

    //  Whenever the user taps within the UITextView, we'll give the textview the focus, and hide the placeholder if necessary.
    [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap)]];

    //  Whenever the user types something in the UITextView, we'll see if we need to hide/show the placeholder label.
    [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];

    [self checkIfNeedToDisplayPlaceholder];
}
-(NSString*)placeholder
{
    //  Returns our "placeholder" text string
    return objc_getAssociatedObject(self, &kKeyPlaceHolder);
}

#pragma mark - Add a "UILabel" to this UITextView class

NSString const *kKeyLabel = @"kKeyLabel";
-(void)setPlaceholderLabel:(UILabel *)placeholderLabel
{
    //  Stores our new UILabel (which contains our placeholder string)
    objc_setAssociatedObject(self, &kKeyLabel, (id)placeholderLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(keyPressed:) name:UITextViewTextDidChangeNotification object:nil];

    [self checkIfNeedToDisplayPlaceholder];
}
-(UILabel*)placeholderLabel
{
    //  Returns our new UILabel
    return objc_getAssociatedObject(self, &kKeyLabel);
}
@end

Yup, ini banyak kode, tapi begitu Anda sudah menambahkannya ke proyek Anda dan menyertakan file .h ...

#import "UITextViewHelper.h"

... Anda dapat dengan mudah menggunakan placeholder di UITextViews.

Ada satu gotcha.

Jika kamu melakukan ini:

self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.text = @"Ooooh, hello there";

... placeholder akan muncul di atas teks. Saat Anda menetapkan textnilainya, tidak ada notifikasi reguler yang dipanggil, jadi saya tidak tahu cara memanggil fungsi saya untuk memutuskan apakah akan menampilkan / menyembunyikan placeholder.

Solusinya adalah dengan mengatur textValuedaripada text:

self.textViewComments.placeholder = @"(Enter some comments here.)";
self.textViewComments.textValue = @"Ooooh, hello there";

Atau, Anda dapat mengatur textnilainya, lalu menelepon checkIfNeedToDisplayPlaceholder.

self.textViewComments.text = @"Ooooh, hello there";
[self.textViewComments checkIfNeedToDisplayPlaceholder];

Saya suka solusi seperti ini, karena mereka "mengisi celah" antara apa yang Apple berikan kepada kami, dan apa yang sebenarnya kami (sebagai pengembang) butuhkan dalam aplikasi kami. Anda menulis kode ini satu kali, menambahkannya ke perpustakaan Anda dari file "helper" .m / .h, dan, seiring waktu, SDK sebenarnya mulai menjadi kurang membuat frustrasi.

(Saya menulis pembantu serupa untuk menambahkan tombol "jelas" ke UITextViews saya, hal lain yang mengganggu UITextFieldtetapi tidak di UITextView...)

Mike Gledhill
sumber
Saya suka betapa bersihnya ini, tapi saya tidak suka bagaimana ini membutuhkan UIView / UILabel kedua (dan tidak benar-benar mewarisi atribut / warna / font dengan mudah dari UITextView). Kontribusi yang bagus
mattsven
6

Pertama-tama ambil label dalam file .h.

Di sini saya ambil

UILabel * lbl;

Kemudian di .m di bawah viewDidLoad mendeklarasikannya

lbl = [[UILabel alloc] initWithFrame:CGRectMake(8.0, 0.0,250, 34.0)];

lbl.font=[UIFont systemFontOfSize:14.0];

[lbl setText:@"Write a message..."];

[lbl setBackgroundColor:[UIColor clearColor]];

[lbl setTextColor:[UIColor lightGrayColor]];

[textview addSubview:lbl];

textview adalah TextView saya.

Sekarang nyatakan

-(void)textViewDidChange:(UITextView *)textView {

 if (![textView hasText]){

    lbl.hidden = NO;

 }
 else{
    lbl.hidden = YES;
 }

}

Dan placeholder Textview Anda siap!

Tania S
sumber
6

Saya merekomendasikan penggunaan pod 'UITextView + Placeholder'

pod 'UITextView+Placeholder'

pada kode Anda

#import "UITextView+Placeholder.h"

////    

UITextView *textView = [[UITextView alloc] init];
textView.placeholder = @"How are you?";
textView.placeholderColor = [UIColor lightGrayColor];
Felix Cruz
sumber
5
    - (void)textViewDidChange:(UITextView *)textView
{
    placeholderLabel.hidden = YES;
}

letakkan label di atas tampilan teks.

vatti
sumber
Atau bahkan lebih baik, Anda dapat menampilkannya kembali ketika tidak ada teks: lblPlaceholder.hidden =! [TextView.text isEqualToString: @ ""];
Despotovic
Saya suka solusi bersih ini, tanpa injeksi ke tampilan teks itu sendiri.
Itachi
5

Tidak mungkin membuat placeholder di UITextView tetapi Anda dapat menghasilkan efek seperti placeholder dengan ini.

  - (void)viewDidLoad{      
              commentTxtView.text = @"Comment";
              commentTxtView.textColor = [UIColor lightGrayColor];
              commentTxtView.delegate = self;

     }
       - (BOOL) textViewShouldBeginEditing:(UITextView *)textView
     {
         commentTxtView.text = @"";
         commentTxtView.textColor = [UIColor blackColor];
         return YES;
     }

     -(void) textViewDidChange:(UITextView *)textView
     {

    if(commentTxtView.text.length == 0){
        commentTxtView.textColor = [UIColor lightGrayColor];
        commentTxtView.text = @"Comment";
        [commentTxtView resignFirstResponder];
    }
    }

ATAU Anda dapat menambahkan label dalam tampilan teks seperti

       lbl = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 0.0,textView.frame.size.width - 10.0, 34.0)];


[lbl setText:kDescriptionPlaceholder];
[lbl setBackgroundColor:[UIColor clearColor]];
[lbl setTextColor:[UIColor lightGrayColor]];
textView.delegate = self;

[textView addSubview:lbl];

dan mengatur

- (void)textViewDidEndEditing:(UITextView *)theTextView
{
     if (![textView hasText]) {
     lbl.hidden = NO;
}
}

- (void) textViewDidChange:(UITextView *)textView
{
    if(![textView hasText]) {
      lbl.hidden = NO;
}
else{
    lbl.hidden = YES;
 }  
}
PJR
sumber
5

Ini meniru placeholder UITextField dengan sempurna, tempat teks placeholder tetap sampai Anda benar-benar mengetik sesuatu.

private let placeholder = "Type here"

@IBOutlet weak var textView: UITextView! {
    didSet {
        textView.textColor = UIColor.lightGray
        textView.text = placeholder
        textView.selectedRange = NSRange(location: 0, length: 0)
    }
}

extension ViewController: UITextViewDelegate {

    func textViewDidChangeSelection(_ textView: UITextView) {
        // Move cursor to beginning on first tap
        if textView.text == placeholder {
            textView.selectedRange = NSRange(location: 0, length: 0)
        }
    }

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if textView.text == placeholder && !text.isEmpty {
            textView.text = nil
            textView.textColor = UIColor.black
            textView.selectedRange = NSRange(location: 0, length: 0)
        }
        return true
    }

    func textViewDidChange(_ textView: UITextView) {
        if textView.text.isEmpty {
            textView.textColor = UIColor.lightGray
            textView.text = placeholder
        }
    }
}
AmitP
sumber
4

Inilah cara lain untuk melakukannya, yang mereproduksi sedikit lekukan UITextFieldplaceholder:

Seret ke UITextFieldkanan di bawah UITextViewsehingga sudut kiri atas mereka sejajar. Tambahkan teks placeholder Anda ke bidang teks.

Di viewDidLoad, tambahkan:

[tView setDelegate:self];
tView.contentInset = UIEdgeInsetsMake(-8,-8,0,0);
tView.backgroundColor = [UIColor clearColor];

Kemudian tambahkan:

- (void)textViewDidChange:(UITextView *)textView {
    if (textView.text.length == 0) {
        textView.backgroundColor = [UIColor clearColor];            
    } else {
        textView.backgroundColor = [UIColor whiteColor];
    }
}
Chris
sumber
4

Mari kita membuatnya mudah

Buat satu UILabel dan letakkan di tampilan teks Anda (Berikan teks sebagai warna placeholder-set abu-abu - Anda dapat melakukan semua ini di xib Anda) Sekarang di file header Anda mendeklarasikan UILabel dan juga textviewDelegate Sekarang Anda cukup menyembunyikan label ketika Anda mengklik tampilan teks

kode lengkap di bawah ini

tajuk

@interface ViewController :UIViewController<UITextViewDelegate>{
 }
   @property (nonatomic,strong) IBOutlet UILabel *PlceHolder_label;
   @property (nonatomic,strong) IBOutlet UITextView *TextView;

@end

penerapan

@implementation UploadFoodImageViewController
@synthesize PlceHolder_label,TextView;

  - (void)viewDidLoad
    {
       [super viewDidLoad];
    }


 - (BOOL)textViewShouldBeginEditing:(UITextView *)textView{

       if([textView isEqual:TextView]){
            [PlceHolder_label setHidden:YES];
            [self.tabScrlVw setContentOffset:CGPointMake(0,150) animated:YES];
          }
      return YES;
    }

@akhir

Jangan lupa untuk menghubungkan textView dan UILabel ke pemilik file dari xib

Nithin M Keloth
sumber
4

Lihatlah UTPlaceholderTextView .

Ini adalah subkelas UITextView yang nyaman yang mendukung serupa placeholder dengan UITextField. Kekhasan utama:

  • Tidak menggunakan subview
  • Tidak mengesampingkan drawRect:
  • Placeholder bisa panjang sewenang-wenang, dan diterjemahkan dengan cara yang sama seperti teks biasa
Granfalloner
sumber
4

Saya membaca semua ini, tetapi datang dengan solusi, Swift 3, yang sangat singkat yang telah bekerja di semua tes saya. Itu bisa bertahan sedikit lebih umum, tetapi prosesnya sederhana. Inilah keseluruhan hal yang saya sebut "TextViewWithPlaceholder".

import UIKit

class TextViewWithPlaceholder: UITextView {

    public var placeholder: String?
    public var placeholderColor = UIColor.lightGray

    private var placeholderLabel: UILabel?

    // Set up notification listener when created from a XIB or storyboard.
    // You can also set up init() functions if you plan on creating
    // these programmatically.
    override func awakeFromNib() {
        super.awakeFromNib()

        NotificationCenter.default.addObserver(self,
                                           selector: #selector(TextViewWithPlaceholder.textDidChangeHandler(notification:)),
                                           name: .UITextViewTextDidChange,
                                           object: self)

        placeholderLabel = UILabel()
        placeholderLabel?.alpha = 0.85
        placeholderLabel?.textColor = placeholderColor
    }

    // By using layoutSubviews, you can size and position the placeholder
    // more accurately. I chose to hard-code the size of the placeholder
    // but you can combine this with other techniques shown in previous replies.
    override func layoutSubviews() {
        super.layoutSubviews()

        placeholderLabel?.textColor = placeholderColor
        placeholderLabel?.text = placeholder

        placeholderLabel?.frame = CGRect(x: 6, y: 4, width: self.bounds.size.width-16, height: 24)

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

    // Whenever the text changes, just trigger a new layout pass.
    func textDidChangeHandler(notification: Notification) {
        layoutSubviews()
    }
}
P. Ent
sumber
Beberapa kekhawatiran di sini. Anda seharusnya tidak menelepon layoutSubviews()langsung. Dan Anda tidak menghapus pengamat NotificationCenter.
Hlung
4

Saya telah menulis sebuah kelas dengan cepat. Anda dapat mengimpor kelas ini kapan pun diperlukan.

import UIKit

CustomTextView kelas publik: 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)
}

}

masukkan deskripsi gambar di sini

Sujatha Girijala
sumber
1
Ini sebenarnya adalah salah satu solusi terbersih yang saya dapat temukan dan akhirnya saya menggunakan ini .. Terutama mempertimbangkan insets dan menggunakan batasan untuk label adalah sentuhan yang bagus, saya belum melihat banyak (ada?) Solusi lain mengambil mengurus mengubah batas, font, RTL dll.
Tandai