UITextView içinde yer tutucu


718

Uygulamam bir UITextView. Şimdi UITextViewsizin için ayarlayabileceğinize benzer bir yer tutucusuna sahip olmak istiyorum UITextField.

Bu nasıl yapılır?


Three20'nin TTTextEditor'u (kendisi UITextField kullanarak) yer tutucu metnin yanı sıra yüksekliğe göre de büyümeyi destekler (bir UITextView'e dönüşür).
Josh Benjamin


20
UITextView + Yer Tutucu kategorisini kullanmaya ne dersiniz? github.com/devxoul/UITextView-Placeholder
devxoul

2
@ Devxoul'un çözümü alt kategoriyi değil kategoriyi kullanır çünkü tercih ederim. Ayrıca, IB denetçisinde 'yer tutucu' seçenekleri (yer tutucu metni ve metin rengi) için bir alan oluşturur. Bazı ciltleme teknikleri kullanır. Ne harika bir kod
samthui7

Eğer UITextViewçözümü kullanıyorsanız oldukça farklı hale gelir. İşte birkaç çözüm. Yüzer Yer Tutucu ve Sahte Yerli Yer
Tutucular

Yanıtlar:


672

Bir Xibdosyadan başlatma , metin sarma ve arka plan rengini korumak için bcd'nin çözümünde birkaç küçük değişiklik yaptım . İnşallah başkalarına sorun kurtaracak.

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

2
bazı durumlarda (özellikle iOS 5 uyumluluğu) macunun geçersiz kılınması gerekir: - (geçersiz) macun: (id) sender {[super paste: sender]; [self textChanged: nil]; }
Martin Ullrich

3
İyi şeyler! NSString (veya NSMutableXXX eşdeğeri olan herhangi bir sınıf) için en iyi uygulamalar hakkında hatırlatma özelliği, özellik "kopyala" değil "kopyala" olmalıdır.
Oli

2
Bu kodu nasıl somutlaştırıyorsunuz? Yer tutucu metin görmüyorum ve yazmaya başladığımda hiçbir şey silinmiyor.
user798719

40
Bu çok, çok kötü yazılmış bir uygulamadır. Dikte değişikliklerini de izleyen çok daha temiz bir sürüm: github.com/cbowns/MPTextView
cbowns

10
DrawRect içindeki görünüm hiyerarşisini değiştirmeyin.
Karmeye

634

Kolay yolla, UITextViewaşağıdaki UITextViewDelegateyöntemleri kullanarak yer tutucu metin oluşturun :

- (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];
}

sadece myUITextViewyaratılıştaki tam metinle ayarlamayı unutmayın.

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

ve UITextViewDelegatebu yöntemleri dahil etmeden önce ana sınıfı a yapın;

@interface MyClass () <UITextViewDelegate>
@end

Swift 3.1 için kod

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

sadece myUITextViewyaratılıştaki tam metinle ayarlamayı unutmayın.

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

ve UITextViewDelegatebu yöntemleri dahil etmeden önce ana sınıfı a yapın;

class MyClass: UITextViewDelegate
{

}

1
Bu 1 UITextView ile 1 ekran için harika (basit seviyorum). Daha karmaşık çözümlerin nedeni, MANY ekranlar ve MANY UITextViews ile daha büyük bir uygulamanız varsa, bunu tekrar tekrar yapmak istememenizdir. Muhtemelen UITextView'ı ihtiyaçlarınıza göre alt sınıflara ayırmak ve sonra kullanmak istersiniz.
ghostatron

42
Birisi metin kutusuna "yer tutucu metni burada ..." yazarsa, yer tutucu metni gibi davranır. Ayrıca, gönderim sırasında tüm bu kriterleri kontrol etmeniz gerekecektir.
Anindya Sengupta

7
Yer tutucu metnin, alan yanıt verdiğinde bile gösterilmesi gerekir ve bu yöntem bunun için çalışmaz.
phatmann

17
@jklp Ben "aşırı mühendislik" yolu daha temiz ve daha yeniden kullanılabilir olduğunu iddia ediyorum ... ve textbiraz hoş metin görünümü özniteliğine kurcalamıyor gibi görünüyor ... oysa bu yöntem onu ​​değiştirir
Cameron Askew

2
temsilci yöntemlerinde neden FerstResponder ve resignFirstResponder çağrıları?
Adam Johns

119

Biraz ağır oldukları için gönderilen çözümlerden hiç memnun kalmadım. Görünüme görünüm eklemek gerçekten ideal değil (özellikledrawRect: ). Her ikisinin de sızıntıları vardı, bu da kabul edilemez.

İşte benim çözüm: 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

Alt görünümleri kullanmadığı (veya sızıntıları olmadığı) için diğerlerinden çok daha basittir. Kullanmaktan çekinmeyin.

Güncelleme 11/10/11: Artık belgelenmiştir ve Interface Builder'da kullanımı desteklemektedir.

Güncelleme 11/24/13: Yeni repo'yu gösterin .


Çözümünüzü beğendim ve setTextmetin özelliğini programlı olarak değiştirirken yer tutucuyu da güncellemek için bir geçersiz kılma ekledim : - (void) setText: (NSString *) string {[super setText: string]; [self _updateShouldDrawPlaceholder]; }
olegueret

1
Çözümünüzü de beğendim ama uyanık yöntemini kaçırdınız, böylece init yönteminiz her zaman çağrılmayacak. Buradaki diğerlerinden aldım.
toxaq

Not - sihirli sayılar yazı tipi boyutuna bağlı olarak değişir. Tam konumlandırma yazı tipinden hesaplanabilir, ancak muhtemelen bu uygulama için buna değmez. Yer tutucunun doğru konumlandırması, metin olmadığında imleç konumunun sağında 2 piksel olmalıdır.
21'de hatırlıyor

Uçtan yüklemeyi çözmek için: muhtemelen bir - (id) initWithCoder: (NSCoder *) aDecoder eklemek istersiniz; mevcut olana eşlik etmek için başlatıcı.
Joris Kluivers

Bu tatlı. Ancak notificationargüman son yöntemde yanlış yazılmış ve düzenleme olarak gönderilecek bir değişiklik çok küçük.
Phil Calvin

53

Kendimi bir yer tutucuyu taklit etmenin çok kolay bir yolunu buldum

  1. NIB veya kodda textView öğenizin textColor'ını lightGrayColor olarak ayarlayın (çoğu zaman)
  2. textView temsilcinizin dosyanın sahibine bağlı olduğundan emin olun ve UITextViewDelegate'i başlık dosyanıza uygulayın
  3. metin görünümünüzün varsayılan metnini şu şekilde ayarlayın (örnek: "Foobar yer tutucusu")
  4. uygulamak: (BOOL) textViewShouldBeginEditing: (UITextView *) textView

Düzenle:

Metin yerine etiketleri karşılaştırmak için if ifadeleri değiştirildi. Kullanıcı metnini sildiyse, yer tutucunun bir bölümünü yanlışlıkla silmek de mümkündür. @"Foobar placeholder"Bu, kullanıcının metne yeniden girmesi anlamına geliyordu Aşağıdaki temsilci yöntemini kullandığı takdirde, -(BOOL) textViewShouldBeginEditing:(UITextView *) textViewbeklendiği gibi çalışmaz. If ifadesindeki metnin rengiyle karşılaştırmayı denedim, ancak arayüz oluşturucusunda ayarlanan açık gri rengin kodla ayarlanan açık gri renkle aynı olmadığını buldum[UIColor lightGreyColor]

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

Klavye döndüğünde ve [textView uzunluğu] == 0 olduğunda yer tutucu metni sıfırlamak da mümkündür

DÜZENLE:

Sadece son kısmı daha net hale getirmek için - yer tutucu metnini şu şekilde ayarlayabilirsiniz:

- (void)textViewDidChange:(UITextView *)textView
{
   if([textView.text length] == 0)
   {
       textView.text = @"Foobar placeholder";
       textView.textColor = [UIColor lightGrayColor];
       textView.tag = 0;
   }
}

12
Bu yaklaşımı çok seviyorum! Yukarıdaki düzenlemeye yapacağım tek şey, uygulamayı textViewDidChange: yönteminden ve textViewDidEndEditing: yöntemine taşımaktır, böylece yer tutucu metin yalnızca nesneyle çalışmayı bitirdikten sonra geri döner.
horseshoe7

52

Ne yapabilirsiniz bazı başlangıç değeri ile metin görünümü kurulur textmülke ve değiştirmek textColoriçin [UIColor grayColor]veya buna benzer. Ardından, metin görünümü düzenlenebilir hale geldiğinde, metni temizleyin ve bir imleç gösterin ve metin alanı tekrar boşsa, yer tutucu metninizi geri koyun. Rengi [UIColor blackColor]uygun şekilde değiştirin.

Bir UITextField'daki yer tutucu işleviyle tam olarak aynı değildir, ancak yakındır.


9
Her zaman yer tutucu metnin rengiyle eşleşiyor gibi görünen lightGrayColor kullandım .
Bill

Ben sadece şimdi okuyorum, ama renk siyah sıfırlama ve textViewShouldBeginEditing metin özelliğini sıfırlama eklemek istiyorum: (UITextView *) textView çok iyi çalışıyor. Bu, aşağıdaki çözümlerle karşılaştırıldığında çok güzel ve hızlı bir çözümdür (ancak yine de aşağıdaki zarif çözümler, uitextview alt sınıfı. Çok daha modüler).
Enrico Susatyo

3
Doğru, ancak düzenleme başladığında değil, yalnızca kullanıcı bir şey yazdığında yer tutucu metninin yerini alan ve düzenleme gerçekte bitmediğinde görünümün boş olduğu anda yer tutucuyu tekrar ekleyen UITextField'in davranışını taklit etmez.
Ash

47

Üzerinde etiketi ayarlayabilirsiniz UITextViewtarafından

[UITextView addSubView:lblPlaceHoldaer];

ve TextViewdidChangeyöntemde gizleyin .

Bu basit ve kolay bir yoldur.


45

Birisi Swift için bir Çözüme ihtiyaç duyarsa:

UITextViewDelegate'i sınıfınıza ekleyin

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

Bu Tamam ama yeterince iyi değil. kullanıcı "Yer Tutucu Metni ..."
yazarsa

45

Basit Swift 3 çözümü

Ekle UITextViewDelegateSınıfınıza

Ayarlamak yourTextView.delegate = self

Oluşturun placeholderLabelve içine yerleştirinyourTextView

Şimdi sadece animasyon placeholderLabel.alphaüzerine 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
      }
    }
  }

placeholderLabeldoğru şekilde ayarlamak için pozisyonla oynamak zorunda kalabilirsiniz , ancak bu çok zor olmamalı


1
Harika cevap, basit çözüm. Animasyona yalnızca alfa değişmesi gerektiğinde küçük bir gelişme ekledim: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

KmKndy'nin cevabını genişlettim, böylece yer tutucu UITextViewsadece dokunmak yerine kullanıcı düzenlemeye başlayana kadar görünür kalır . Bu, Twitter ve Facebook uygulamalarındaki işlevselliği yansıtır. Çözümüm, kullanıcı doğrudan yazı yazıyorsa veya metin yapıştırıyorsa alt sınıf yapmanızı gerektirmez!

Yer Tutucu Örneği Twitter Uygulaması

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

myUITextView'ı oluşturmadaki tam metinle ayarlamayı unutmayın.

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

ve bu yöntemleri eklemeden önce üst sınıfı bir UITextView temsilcisi olun.

@interface MyClass () <UITextViewDelegate>
@end

20

Kullanmanızı tavsiye ederim SZTextView.

https://github.com/glaszig/SZTextView

Senin varsayılan ekleyin UITextViewgelen storyboardve daha sonra onun özel bir sınıf değiştirmek SZTextViewaşağıda gibi 👇👇👇👇

resim açıklamasını buraya girin

Sonra new 'da iki yeni seçenek Attribute Inspectorgöreceksiniz.

resim açıklamasını buraya girin


20

Aşağıda "SAMTextView" ObjC kodunun bir Swift portu sorusuna ilk cevaplardan biri olarak yayınlanmıştır. İOS 8'de test ettim. Orijinal çok yüksek ve çok sağ olduğu için yer tutucu metnin yerleştirilmesi için sınırlar da dahil olmak üzere birkaç şey ayarladım (bu yayına yapılan yorumlardan birinde öneri kullanıldı).

Çok basit çözümler olduğunu biliyorum, ancak UITextView alt sınıflandırma yaklaşımını seviyorum çünkü bu yeniden kullanılabilir ve mekanizmaları ile kullanarak sınıflar dağınıklık zorunda değilsiniz.

Hızlı 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)
    }
}

Hızlı 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)
    }
}

hızlı sürümü yapmak için teşekkürler, sadece süper çağırmak bir awakeFromNib yöntemi sahip olmanın ne anlamı açıklayabilir misiniz?
Pierre

Yer tutucuyu ayarlar, ancak yazmaya başladıktan sonra güncellenmez.
David

Boşver, bildirim çağrısını awakeFromNib'e koydum ve şimdi çalışıyor.
David

12

ben böyle yaptım:

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

12

İşte tam olarak UITextField'ın yer tutucusu gibi davranan, ancak özel görünümler çizmeyi veya ilk yanıtlayıcıyı istifa etmeyi gerektirmeyen daha kolay bir çözüm.

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

}

(ifadenin hiçbir şeyin girilmediği ve kullanıcının geri tuşuna bastığı durumda başka bir ifadenin ikinci kontrolü)

Sadece sınıfınızı bir UITextViewDelegate olarak ayarlayın. ViewDidLoad'da aşağıdaki gibi başlatmanız gerekir

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

2
Şey, kullanıcı "yer tutucu metin" caret ortasında bir yere dokunursa orada kalır.
Alex Sorokoletov

10

Merhaba, IQKeyboard Manager'da bulunan IQTextView'u kullanabilirsiniz ve sadece metin görünümünüzün ayarlanmış sınıfını IQTextView ile entegre etmek kolaydır ve yer tutucu etiketi istediğiniz renkle ayarlamak için özelliğini kullanabilirsiniz. Kütüphaneyi IQKeyboardManager'dan indirebilirsiniz

ya da kokoapodlardan kurabilirsiniz.


IQKeyboardManager çok kullanışlı ve kodsuzdur. Benim için en iyi cevap!
NSDeveloper

1
Aslında bu nedenle yorum yapıyorum ve yorum yapıyorum. IQTextView'ın daha önce IQKeyboardManager'da mevcut olduğunu bilmiyorum.
NSDeveloper

Delege ile ilgili bir sorunum vardı. Delege geçersiz kılma ve UITextViewDelegateiyi çalıştı
sınıftan çıktım

underated answer
grantespo

10

Başka bir cevap eklemek için özür dilerim, ama böyle bir şey çıkardım ve bu, UITextField türüne en yakın yer tutucuyu yarattı.

Umarım bu birine yardımcı olur.

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

1
İlk if deyimindeki komutların sırasını değiştirmek zorunda kaldım if(textView.textColor == [UIColor lightGrayColor]){ textView.textColor = [UIColor blackColor]; textView.text = [textView.text substringToIndex: 1]; Aksi takdirde metin görünümüne girilen ilk karakter metnin sonuna yerleştirildi
Flexicoder

7

Bunu bir kod satırı içinde kullanmanın basit yolu:

Bu etiketi kodunuza bağladıktan sonra .nib'de UITextView'e kadar bir etiket alın.

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

7

Sam Soffes'in uygulamasını iOS7 ile çalışacak şekilde değiştirdim:

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

_placeholderAttribues = nilYazı tipini değiştirebilecek yöntemleri ve bunları etkileyebilecek diğer temaları ayarlamayı unutmayın . Ayrıca, sizi rahatsız etmiyorsa öznitelikler sözlüğünün "tembel" yapımını atlamak isteyebilirsiniz.

DÜZENLE:

Yer tutucunun otomatik yerleşim animasyonlarından ve benzerlerinden sonra iyi görünmesini istiyorsanız setNeedsDisplay'i setBounds'un geçersiz kılınmış bir sürümünde aramayı unutmayın.


Ben offset x parametresine insets.left eklemeniz gerektiğini düşünüyorum.
Karmeye

setBounds yerine setFrame değil mi?
JakubKnejzlik

Hayır! Görünüşte düzen animasyonları sırasında setFrame çağrılmaz.
Nailer

6

Ayrıca UITextView alt sınıfı olarak yeni bir TextViewWithPlaceholder sınıfı oluşturabilirsiniz.

(Bu kod biraz kaba - ama bence doğru yolda.)

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

}

Temsilcinize şunu ekleyin:

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

}

1
Eğer drawRect geçersiz kılarak kendi yer tutucu boyamak gerektiğini kesin davranışı elde etmek için: (tutucu çizmek yalnızca [öz isFirstResponder] && [[öz metin] uzunluk] == 0!) BecomeFirstResponder ve resignFirstResponder iç ve çağıran setNeedsDisplay
rpetrich

6

'UITextView' alt sınıfının kendi versiyonunu yaptım. Sam Soffes'in bildirimleri kullanma fikrini beğendim , ancak drawRect: overwrite'ı beğenmedim. Bana aşırı geldi. Bence çok temiz bir uygulama yaptım.

Alt sınıfıma buradan bakabilirsiniz . Bir demo projesi de dahildir.


6

Bu iş parçacığının birçok yanıtı vardı, ama burada tercih ettiğim sürüm.

Bu uzanır mevcut UITextViewsınıf o kadar kolay reuseable olduğunu ve yok gibi olayları kesmek textViewDidChange(bunlar zaten başka bir yerde bu olayları müdahale olsaydı, kullanıcının kodu bozabilir).

Kodumu kullanarak (aşağıda gösterilmiştir), aşağıdakilerden herhangi birine kolayca bir yer tutucu ekleyebilirsiniz UITextViews:

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

Bu yeni tutucu değerini ayarladığınızda, sessizce bir ekler UILabelsenin üstünde UITextViewgerekli, o zaman gizlemek / gösteriler it:

resim açıklamasını buraya girin

Tamam, bu değişiklikleri yapmak için şu kodu içeren bir "UITextViewHelper.h" dosyası ekleyin:

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

... ve bunu içeren bir UITextViewHelper.m dosyası:

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

Evet, çok fazla kod var, ancak projenize ekledikten ve .h dosyasını ekledikten sonra ...

#import "UITextViewHelper.h"

... içinde yer tutucuları kolayca kullanabilirsiniz UITextViews.

Yine de bir tane var.

Eğer bunu yaparsan:

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

... yer tutucu metnin üstünde görünür . textDeğeri ayarladığınızda, normal bildirimlerin hiçbiri çağrılmaz, bu nedenle yer tutucunun gösterilip gösterilmeyeceğine / gizleneceğine karar vermek için işlevimi nasıl arayacağımı öğrenemedim.

Çözüm, aşağıdakileri textValueyerine ayarlamaktır text:

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

Alternatif olarak, textdeğeri ayarlayabilir ve sonra arayabilirsiniz checkIfNeedToDisplayPlaceholder.

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

Apple'ın bize sağladıkları ile bizim (geliştiriciler olarak) gerçekten ihtiyaç duyduğumuz şey arasındaki “boşluğu doldurdukları” gibi, bu tür çözümleri seviyorum. uygulamalarımızda . Bu kodu bir kez yazar, "helper" .m / .h dosyaları kitaplığınıza eklersiniz ve zamanla SDK daha az sinir bozucu olmaya başlar.

(UITextViews'e "temiz" bir düğme eklemek için benzer bir yardımcı yazdım, can sıkıcı bir şekilde var olan UITextFieldama değil başka bir şey UITextView...)


Ne kadar temiz olduğunu seviyorum, ama nasıl ikinci bir UIView / UILabel gerektirir sevmiyorum (ve gerçekten UITextView kolayca öznitelikleri / renkleri / yazı tipi miras değil). Yine de güzel katkı
mattsven

6

Önce .h dosyasında bir etiket alın.

Al bakalım

UILabel * lbl;

Sonra viewDidLoad altında .m altında beyan

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 benim TextView.

Şimdi beyan et

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

 if (![textView hasText]){

    lbl.hidden = NO;

 }
 else{
    lbl.hidden = YES;
 }

}

Textview yer tutucunuz hazır!


6

'UITextView + Placeholder' bölmesini kullanmanızı öneririm

pod 'UITextView+Placeholder'

kodunda

#import "UITextView+Placeholder.h"

////    

UITextView *textView = [[UITextView alloc] init];
textView.placeholder = @"How are you?";
textView.placeholderColor = [UIColor lightGrayColor];

5
    - (void)textViewDidChange:(UITextView *)textView
{
    placeholderLabel.hidden = YES;
}

metin görünümünün üzerine bir etiket koyun.


Ya da daha iyisi, metin olmadığında tekrar gösterebilirsiniz: lblPlaceholder.hidden =! [TextView.text isEqualToString: @ ""];
Despotovic

Bu temiz çözümü beğendim, metin görünümüne enjeksiyon yapılmadı.
Itachi

5

UITextView'da yer tutucu oluşturmak mümkün değildir, ancak bununla yer tutucu gibi efekt üretebilirsiniz.

  - (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];
    }
    }

VEYA metin görünümünde olduğu gibi etiket ekleyebilirsiniz

       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];

ve ayarla

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

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

5

Bu, gerçekten bir şey yazana kadar yer tutucu metnin kaldığı UITextField'ın yer tutucusunu mükemmel bir şekilde taklit eder.

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

4

İşte bunu yapmanın başka bir yolu, UITextFieldyer tutucusunun hafif girintisini yeniden üreten :

Sürükleyin UITextFieldUITextViewSol üst köşeleri hizalı olacak şekilde sağ altına . Yer tutucu metninizi metin alanına ekleyin.

ViewDidLoad'da şunları ekleyin:

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

Sonra Ekle:

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

4

Kolaylaştıralım

Bir UILabel oluşturun ve metin görünümünüze yerleştirin (Metni Yer Tutucu ayarlı renk gri olarak verin-tüm bunları xib'inizde yapabilirsiniz) Şimdi başlık dosyasında UILabel ve ayrıca textviewDelegate'i şimdi etiketin gizleyebilirsiniz metin görünümünü tıkladığınızda

aşağıdaki kodun tamamı

başlık

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

@end

uygulama

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

@son

TextView ve UILabel öğelerini xib'den dosya sahibine bağlamayı unutmayın


4

UTPlaceholderTextView'a bir göz atın .

Bu, UITextField ile aynı yer tutucuyu destekleyen uygun bir UITextView alt sınıfıdır. Ana özellikler:

  • Alt görünüm kullanmaz
  • DrawRect'i geçersiz kılmaz:
  • Yer tutucu isteğe bağlı uzunlukta olabilir ve normal metinle aynı şekilde oluşturulabilir

4

Tüm bunları okudum, ancak tüm testlerimde işe yarayan çok kısa bir Swift 3 çözümü buldum. Biraz daha genelliğe dayanabilir, ancak süreç basittir. İşte "TextViewWithPlaceholder" olarak adlandırdığım tüm şey.

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

Burada bazı endişeler var. Sen buna olmamalıdır layoutSubviews()doğrudan. NotificationCenter gözlemcisini kaldırmadınız.
Hlung

4

Hızlı bir şekilde bir sınıf yazdım. Bu sınıfı gerektiğinde içe aktarabilirsiniz.

import UIKit

genel sınıf 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)
}

}

resim açıklamasını buraya girin


1
Bu aslında bulabildiğim en temiz çözümlerden biri ve bunu kullandım. sınırların, yazı tiplerinin, RTL'nin vb. bakımı
Mark
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.