Заполнитель в UITextView
Я делаю приложение, которое использует UITextView
. Теперь я хочу UITextView
чтобы иметь заполнитель, подобный тому, который вы можете установить для UITextField
.
кто-нибудь знает, как это сделать?
30 ответов:
я внес несколько незначительных изменений в решение bcd, чтобы разрешить инициализацию из
Xib
файл, обертывание текста, а также для поддержания цвета фона. Надеюсь, это избавит других от неприятностей.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.м:
#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
простой способ, просто создать замещающий текст в
UITextView
С помощью следующейUITextViewDelegate
методы:- (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]; }
только не забудьте установить
myUITextView
С точным текстом, на создание, например,UITextView *myUITextView = [[UITextView alloc] init]; myUITextView.delegate = self; myUITextView.text = @"placeholder text here..."; myUITextView.textColor = [UIColor lightGrayColor]; //optional
и сделать родительский класс
UITextViewDelegate
перед включением этих методов, например,@interface MyClass () <UITextViewDelegate> @end
код для 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() }
только не забудьте установить
myUITextView
С точным текстом, на создание, например,let myUITextView = UITextView.init() myUITextView.delegate = self myUITextView.text = "placeholder text here..." myUITextView.textColor = .lightGray
и сделать родительский класс
UITextViewDelegate
перед включением этих методов, например,class MyClass: UITextViewDelegate { }
Я не был слишком доволен ни одним из решений, опубликованных, поскольку они были немного тяжелыми. Добавление представлений в представление на самом деле не идеально (особенно в
drawRect:
). У них обоих были утечки, что тоже неприемлемо.вот мое решение: 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.м
// // 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
Это намного проще, чем другие, так как он не использует subviews (или имеет утечки). Не стесняйтесь использовать оно.
обновление 11/10/11: теперь он документирован и поддерживает использование в Interface Builder.
обновление 11/24/13: укажите на новое РЕПО.
что вы можете сделать, это создать представление текста с некоторым начальным значением в
text
свойства, и изменитьtextColor
to[UIColor grayColor]
или что-то подобное. Затем, когда текстовое представление становится редактируемым, очистите текст и представьте курсор, и если текстовое поле снова пусто, верните текст-заполнитель. Измените цвет на[UIColor blackColor]
по мере необходимости.это не совсем то же самое, что функциональность заполнителя в UITextField, но это близко.
я нашел себе очень простой способ подражать владельцу места
- в СИБ или код свойства textColor установить ваш виджет TextView, чтобы lightGrayColor (большую часть времени)
- убедитесь, что делегат вашего textView связан с владельцем файла и реализует UITextViewDelegate в заголовочном файле
- установите текст по умолчанию для вашего textview (пример: "foobar placeholder")
- реализовать: (BOOL) textViewShouldBeginEditing: (UITextView * ) textView
Edit:
изменены операторы if для сравнения тегов, а не текста. Если пользователь удалил свой текст, то можно было также случайно удалить часть держателя места
@"Foobar placeholder"
.Это означало, что если пользователь повторно ввел textView следующий метод делегата,-(BOOL) textViewShouldBeginEditing:(UITextView *) textView
, это не будет работать, как ожидалось. Я попытался сравнить по цвету текста в операторе if, но обнаружил, что светло-серый цвет, установленный в interface builder, не совпадает с светло-серый цвет задается в коде[UIColor lightGreyColor]
- (BOOL) textViewShouldBeginEditing:(UITextView *)textView { if(textView.tag == 0) { textView.text = @""; textView.textColor = [UIColor blackColor]; textView.tag = 1; } return YES; }
также можно сбросить текст заполнителя при возврате клавиатуры и [TextView length] == 0
EDIT:
просто чтобы сделать последнюю часть более ясной-вот как вы можете установить текст заполнителя обратно:
- (void)textViewDidChange:(UITextView *)textView { if([textView.text length] == 0) { textView.text = @"Foobar placeholder"; textView.textColor = [UIColor lightGrayColor]; textView.tag = 0; } }
вы можете установить метку на
UITextView
by[UITextView addSubView:lblPlaceHoldaer];
и скрыть его на
TextViewdidChange
метод.Это простой и легкий способ.
Если кому-то нужно решение для Swift:
добавить UITextViewDelegate в свой класс
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 } }
простой Swift 3 решение
добавить
UITextViewDelegate
в свой классSet
yourTextView.delegate = self
создать
placeholderLabel
и поместите его внутриyourTextView
теперь просто анимировать
placeholderLabel.alpha
ontextViewDidChange
: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 } } }
возможно, вам придется играть с
placeholderLabel
положение, чтобы настроить его правильно, но это не должно быть слишком трудно
я расширил ответ KmKndy, так что заполнитель остается видимым, пока пользователь не начнет редактировать
UITextView
, а не просто нажимает на нее. Это отражает функциональность в приложениях Twitter и Facebook. Мое решение не требует от вас подкласса и работает, если пользователь вводит непосредственно или вставляет текст!- (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 с точным текстом при создании, например
UITextView *myUITextView = [[UITextView alloc] init]; myUITextView.delegate = self; myUITextView.text = @"What's happening?"; myUITextView.textColor = [UIColor lightGrayColor]; //optional
и сделать родительский класс a Делегат UITextView перед включением этих методов, например
@interface MyClass () <UITextViewDelegate> @end
я рекомендую использовать
SZTextView
.https://github.com/glaszig/SZTextView
добавить по умолчанию
UITextView
Сstoryboard
а затем измените свой пользовательский класс наSZTextView
нижетогда вы увидите два новых варианта в
Attribute Inspector
вот как я это сделал:
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.м
@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
вот более простое решение, которое ведет себя точно так же, как заполнитель UITextField, но не требует рисования пользовательских представлений или отставки первого ответчика.
- (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; } }
(вторая проверка в инструкции else if для случая, когда ничего не вводится и пользователь нажимает backspace)
просто установите свой класс Как UITextViewDelegate. В viewDidLoad вы должны инициализировать как
- (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; }
Ниже приведен Swift-порт ObjC-кода "SAMTextView", опубликованный как один из первых ответов на вопрос. Я тестировал его на iOS 8. Я изменил пару вещей, в том числе смещение границ для размещения текста заполнителя, поскольку оригинал был слишком высоким и слишком правым (используется предложение в одном из комментариев к этому сообщению).
Я знаю, что есть много простых решений, но мне нравится подход подкласс UITextView, потому что он многоразовый и не придется загромождать классы, используя его с механизмами.
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) } }
Извините, что добавляю еще один ответ, но я просто вытащил что-то вроде этого, и это создало самый близкий к UITextField вид заполнителя.
надеюсь, это кому-то поможет.
-(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); } }
привет Вы можете использовать IQTextView доступны в Iqkeyboard Manager это простой в использовании и интеграции просто установить класс вашего textview в IQTextView и вы можете использовать его свойство для установки метки заполнителя с цветом вы хотите. Вы можете скачать библиотеку с IQKeyboardManager
или вы можете установить его с cocoapods.
простой способ использовать это в какой-то строке кода:
Возьмите одну метку до UITextView in .перо подключение этой метки к вашему коду , После него.
- (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; }
Я изменил реализацию Sam Soffes для работы с 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; }
Не забудьте поставить
_placeholderAttribues = nil
в методах, которые могут изменить шрифт и другие thigns, которые могут повлиять на них. Вы также можете пропустить "ленивое" создание словаря атрибутов, если это вас не беспокоит.EDIT:
Не забудьте вызвать setNeedsDisplay в переопределенной версии setBounds, если вам нравится, чтобы заполнитель выглядел хорошо после анимации автозапуска и подобный.
вы также можете создать новый класс TextViewWithPlaceholder как подкласс UITextView.
(этот код довольно грубый - но я думаю, что это на правильном пути.)
@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; } }
в делегате добавьте следующее:
- (void)textViewDidChange:(UITextView *)textView { if ([textView respondsToSelector: @selector(updateForTextChange)]) { [textView updateForTextChange]; } }
Я сделал свою собственную версию подкласса 'UITextView'. Мне понравилось Сэм Soffesидея использования уведомлений, но мне не понравилась drawRect: overwrite. Мне кажется, это перебор. Я думаю, что я сделал очень чисто реализацию.
вы можете посмотреть на моем подкласс здесь. Демо-проект также включен.
этой теме было много ответов, но вот версия, которую я предпочитаю.
это выходит существующей
UITextView
класс так легко повторно использовать, и это не перехват события какtextViewDidChange
(что может нарушить код пользователя, если они уже перехватывали эти события в другом месте).используя мой код (показано ниже), вы можете легко добавить заполнитель в любой из ваших
UITextViews
такой:self.textViewComments.placeholder = @"(Enter some comments here.)";
когда вы установите это новое значение заполнителя, он тихо добавляет
UILabel
поверхUITextView
, затем скрыть/показывает его по мере необходимости:хорошо, чтобы внести эти изменения, добавьте "UITextViewHelper.H-файл", содержащий этот код:
// 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
...и UITextViewHelper.файл м, содержащие этот:
// 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
Да, это много кода, но как только вы добавили его в свой проект и включили .H-файл...
#import "UITextViewHelper.h"
...вы можете легко используйте заполнители в
UITextViews
.есть один gotcha, хотя.
если вы сделаете это:
self.textViewComments.placeholder = @"(Enter some comments here.)"; self.textViewComments.text = @"Ooooh, hello there";
...появится заполнитель на текст. Когда вы устанавливаете
text
значение, ни одно из регулярных уведомлений не вызывается, поэтому я не мог решить, как вызвать мою функцию, чтобы решить, показывать/скрывать заполнитель.решение состоит в том, чтобы установить
textValue
а неtext
:self.textViewComments.placeholder = @"(Enter some comments here.)"; self.textViewComments.textValue = @"Ooooh, hello there";
кроме того, вы можете установить
text
значение, то вызовcheckIfNeedToDisplayPlaceholder
.self.textViewComments.text = @"Ooooh, hello there"; [self.textViewComments checkIfNeedToDisplayPlaceholder];
мне нравятся такие решения, поскольку они "заполняют пробел" между тем, что Apple предоставляет нам, и тем, что мы (как разработчики) на самом деле нужно в наших программах. Вы пишете этот код один раз, добавьте его в свою библиотеку "helper" .м./H файлов, и, со временем, SDK на самом деле начинает становиться все менее разочаровывающим.
(я написал аналогичный помощник для добавления кнопка" Очистить " для моих UITextViews, еще одна вещь, которая досадно существует в
UITextField
а неUITextView
...)
сначала этикетке .H-файл.
ЯUILabel * lbl;
затем в .m под viewDidLoad объявить его
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-это мой TextView.
Теперь объявить
-(void)textViewDidChange:(UITextView *)textView { if (![textView hasText]){ lbl.hidden = NO; } else{ lbl.hidden = YES; } }
и ваш заполнитель Textview готов !
Я рекомендую использовать pod 'UITextView+Placeholder'
pod 'UITextView+Placeholder'
ваш код
#import "UITextView+Placeholder.h" //// UITextView *textView = [[UITextView alloc] init]; textView.placeholder = @"How are you?"; textView.placeholderColor = [UIColor lightGrayColor];
- (void)textViewDidChange:(UITextView *)textView { placeholderLabel.hidden = YES; }
поместите метку поверх textview.
невозможно создать заполнитель в UITextView, но вы можете создать эффект, подобный держателю места.
- (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]; } }
или вы можете добавить метку в textview так же, как
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];
и set
- (void)textViewDidEndEditing:(UITextView *)theTextView { if (![textView hasText]) { lbl.hidden = NO; } } - (void) textViewDidChange:(UITextView *)textView { if(![textView hasText]) { lbl.hidden = NO; } else{ lbl.hidden = YES; } }
вот еще один способ сделать это, тот, который воспроизводит небольшое отступ
UITextField
с заполнителем:перетащите a
UITextField
подUITextView
так, что их верхние левые углы выровнены. Добавьте текст-заполнитель в текстовое поле.в viewDidLoad, добавить:
[tView setDelegate:self]; tView.contentInset = UIEdgeInsetsMake(-8,-8,0,0); tView.backgroundColor = [UIColor clearColor];
потом добавил:
- (void)textViewDidChange:(UITextView *)textView { if (textView.text.length == 0) { textView.backgroundColor = [UIColor clearColor]; } else { textView.backgroundColor = [UIColor whiteColor]; } }
позволяет сделать это легко
создайте один UILabel и поместите его в свой текстовый вид(дайте текст в качестве заполнителя-установите серый цвет-вы можете сделать все это в своем xib) Теперь вы в заголовочном файле объявить UILabel ни, а также в textviewDelegate Теперь вы можете просто скрыть метку при нажатии на textview
полный код ниже
заголовок
@interface ViewController :UIViewController<UITextViewDelegate>{ } @property (nonatomic,strong) IBOutlet UILabel *PlceHolder_label; @property (nonatomic,strong) IBOutlet UITextView *TextView; @end
реализация
@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; }
@end
Не забудьте подключить textView и UILabel в filesowner из xib
посмотри UTPlaceholderTextView.
Это удобный подкласс UITextView, который поддерживает заполнитель, похожий на UITextField. Основные особенности:
- не использует subviews
- не переопределяет drawRect:
- заполнитель может иметь произвольную длину и отображаться точно так же, как обычный текст
Я прочитал все это, но придумал очень короткое, быстрое решение 3, которое работало во всех моих тестах. Он мог бы выдержать немного больше общности, но процесс прост. Вот все, что я называю "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() } }
это идеально имитирует заполнитель UITextField, где текст держателя места остается до тех пор, пока вы не наберете что-то.
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 } } }
Как вставить заполнитель в UITextView?
ответ PJR работает как шарм. Те, что были здесь, не работали на меня. Может быть, дело в iOS5.