In the history of the most complete iOS of UITextView to achieve the placeHolder placeholder text N kinds of methods


IOS development, UITextField and UITextView is the most commonly used text acceptance and text display class controls. Both UITextField and UITextView input text, you can also monitor the text changes. The difference is that UITextField inherits from the UIControl class. UITextView inherits from the UIScrollView entity class. This leads to the fact that UITextView can display content in multiple lines, and it can also roll like UIScrollView. The UITextField can only display a single line of content. From this point of view, UITextView is better than UITextField in function.
, however, as we all know, UITextField has a placeholder attribute, you can set the UITextField placeholder text, play a role in prompting the user to enter the relevant information. However, UITextView was not so lucky, apple did not give UITextView a similar property such as placeholder for developers to use. The development, we often encounter both to occupy the text, but also multi line display and can scroll controls, simple UITextField or UITextView can not meet the needs of this product. For example, most of the app on the market now have a user feedback entrance, as shown in figure (1). Below I will be able to think of ways to summarize it, so that more developers know that there are so many ways to achieve UITextView placeholder text.

In the history of the most complete iOS of UITextView to achieve the placeHolder placeholder text N kinds of methods
diagram (I)

One method

1 use the UITextView property of text as “placeholder”.
2 clears the “placeholder” in the proxy method that started editing”.
3 sets the “placeholder” in the end of the proxy method”.

Features: the characteristic of this method is that when the user clicks the textView placeholder placeholder text will immediately disappear, the official placeholder is listening to the user when the system placeholder will disappear after the text input.

Create a textView UITextView *textView =[[UITextViewalloc]initWithFrame:CGRectMake / (20,70, SCREEN.width-40100)]; textView.backgroundColor= [UIColor whiteColor]; textView.text = @ "placeholder"; textView.textColor [UIColor = grayColor]; textView.delegate = self; [self.view addSubview:textView]; #pragma mark UITextViewDelegate (void) textViewDidEndEditing: (UITextView * textView) {if (textView.text.length < 1) {textView.text = @ "I'm placeholder"; textView.textColor [UIColor = grayColor];}} - (void) textViewDidBeginEditing: (UITextView * textView) {if ([textView.text isEqualToString:@ "placeholder"] "[email protected]"; textView.textColor=[UIColor) {blackColor]}};

Method two

1 create textView
2 to add a UILabel child control, as placeholder
3 in the text of the proxy method to change the show / hide UILabel

Features: this method can also achieve similar to the placeholder function. Compared with the method, the method two can realize the dynamic monitoring of the text changes, not the pop-up keyboard immediately clear placeholder, only when the user begins to enter text. Placeholder will disappear. Similarly, when the user empties the text, placeholder will be displayed again.

#import "WSViewController.h" @interface (WSViewController) < UITextViewDelegate> @property (nonatomic, weak) UITextView *textView @property (nonatomic, weak); UILabel *placeHolder; @end @implementation WSViewController (void) viewDidLoad {[super viewDidLoad]; Do any additional setup after loading / the view. [self setupTextView];} / / add textView (void) {setupTextView UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake (10, 74, SCREEN_WIDTH - 2 * 10, 200]); textView.frame = CGRectMake (10, 74, SCREEN_WIDTH - 2 * 10, 200); [self.view addSubview:textView]; self.textView = textView; textView.contentInset = UIEdgeInsetsMake (-64, 0, 0, 0); textView.delegate = self; [sel F setupPlaceHolder]; / / add a view in the pop-up keyboard to place the exit the Done button on the keyboard UIToolbar * topView = [[UIToolbar alloc] initWithFrame:CGRectMake (0, 0, 320, 30)]; [topView setBarStyle:UIBarStyleDefault]; UIBarButtonItem btnSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace * target:self action:nil] UIBarButtonItem * doneButton = [[UIBarButtonItem; alloc] initWithTitle:@ style:UIBarButtonItemStyleDone target:self action:@selector "finish" (dismissKeyBoard)]; NSArray * buttonsArray = [NSArray arrayWithObjects:btnSpace, doneButton, nil]; [topView setItems:buttonsArray]; [textView setInputAccessoryView:topView];} / / textView to add a UILabel Control - (void) setupPlaceHolder *placeHolder alloc] initWithFrame:CGRectMake {UILabel = [[UILabel (15, -2, SCREEN_WIDTH - 2 * 15, 200]); self.placeHolder = placeHolder; placeHolder.text = @ "placeholder"; placeHolder.textColor [UIColor = lightGrayColor]; placeHolder.numberOfLines = 0; placeHolder.contentMode = UIViewContentModeTop; [self.textView addSubview:placeHolder];} #pragma (- UITextViewDelegate - mark void) textViewDidChange: (UITextView *) textView {if (! TextView.text.length) {self.placeHolder.alpha} {else = 1; self.placeHolder.alpha = 0;}} / / close the keyboard (void) dismissKeyBoard{[self.textView resignFirstResponder] @end;}

The same train of thought, we can also use the UITextField as a placeholder for the UILabel or UITextView to replace, the same can be achieved with placeholder textView, in the second is not detailed.

Method three

1 custom UITextView
2 added to the UITextView placeholder and placeholderColor
3 attribute overrides the initWithFrame method to add
4 notification monitoring text changes
5: set drawRect rewriting methods
6 rewrite related properties

Features: compared regardless of the above two methods, the method of portability developing better, this method not only willing to free through the placeholder property we add the default text, can we add placeholderColor to set the default text color. In the future, we just need to write such a custom UITextView, you can once and for all.

#import < UIKit/UIKit.h> @interface; WSPlaceholderTextView: UITextView / * * * @property placeholder text (nonatomic, copy) NSString *placeholder; / * * * / placeholder text color @property (nonatomic, strong) UIColor *placeholderColor; @end # import "WSPlaceholderTextView.h" @implementation WSPlaceholderTextView (instancetype) - initWithFrame: (CGRect frame) {if (self = [super initWithFrame:frame]) {set the default font [UIFont / / self.font = systemFontOfSize:15]; self.placeholderColor = [UIColor / / color set grayColor]; / / use text to change the notification monitoring (textDidChange:) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector name:UITextViewTextDidChangeNotification Object:self] return self;};} - (void) textDidChange: (NSNotification * Note) {/ / will re call the drawRect: method [self setNeedsDisplay];} - (void) dealloc defaultCenter] {[[NSNotificationCenter removeObserver:self];} / * * * when drawRect: is called, will be removed before painting. * / - (void) drawRect: (CGRect) rect {/ / if there is text, return directly, do not need to draw the placeholder text if (self.hasText) return; NSMutableDictionary *attrs = [NSMutableDictionary dictionary] / / attribute; attrs[NSFontAttributeName] = self.font; attrs[NSForegroundColorAttributeName] = self.placeholderColor; / / draw text rect.origin.x = 5; rect.origin.y = 8; rect.size.width = 2 * rect.origin.x; [self.placeholder drawInRect:rect withAttributes:attrs] (void);} - layoutSubviews {[super layoutSubviews]; [self setNeedsDisplay];} #pragma mark - setter - (void) setPlaceholder: (NSString * placeholder) {_placeholder [placeholder = copy]; [self setNeedsDisplay];} - (void) setPlaceholderColor: (UIColor * placeholderColor) {_placeholderColor = placeholderColor; [self setNeedsDisplay];} - (void) setFont: (UIFont *) font setFont:font] [self {[super; setNeedsDisplay];} - (void) setText: (NSString * text) {[super setText:text]; [self setNeedsDisplay];} - (void) setAttributedText: (NSAttributedString * attributedText) {[super setAttributedText:attributedText]; [self setNeedsDisplay];} @ End

Method four

1 custom UITextView
2 added to the UITextView placeholder and placeholderColor
3 attribute overrides the initWithFrame method
4 drawRect: set rewriting methods
5 rewrite related properties

Features: this method is similar to the method three, but did not use the notification to monitor changes in the text, the need to cooperate with the text of the textViewDidChanged: to change the use of the proxy method.

#import < UIKit/UIKit.h> @interface; WSTextView: UITextView / * * * @property placeholder text (nonatomic, copy) NSString *placeholder; / * * * / placeholder text color @property (nonatomic, strong) UIColor *placeholderColor; @end #import "WSTextView.h" @implementation WSTextView (instancetype) - initWithFrame: (CGRect frame) {if (self = [super initWithFrame:frame]) {self.font [UIFont = systemFontOfSize:15]; self.placeholderColor = [UIColor lightGrayColor]; self.placeholder = @ "please input";} return self;} / / Only override drawRect: if you perform custom drawing. An empty implementation adversely affects performance / during animation. - (void) drawRect: (CGRect rect) {/ / Drawing code NSMutableDic Tionary *attrs [NSMutableDictionary = dictionary]; attrs[NSFontAttributeName] = self.font; attrs[NSForegroundColorAttributeName] = self.placeholderColor; [self.placeholder drawInRect:CGRectMake (0, 0, self.frame.size.width, self.frame.size.height, withAttributes:attrs]);} / / layout of child controls when the need to redraw - (void) layoutSubviews [self setNeedsDisplay] {[super layoutSubviews];}; / / set the properties you need to redraw, so we need to override the set method the related attributes - (void) setPlaceholder: (NSString * placeholder) {_placeholder = placeholder; [self setNeedsDisplay];} - (void) setPlaceholderColor: (UIColor * placeholderColor) {_placeholderColor = placeholderColor; [self setNeedsDisplay];} - (void) setFo Nt: (UIFont * font) {[super setFont:font]; [self setNeedsDisplay];} - (void) setText: (NSString * text) {[super setText:text]; if (text.length) {/ / because it is in the text change agent method to determine whether the placeholder display, and through the method of proxy code set text way and do not call text change so, this according to text is not null to determine whether the display of placeholder. Self.placeholder = @ "[self setNeedsDisplay]";};} - (void) setAttributedText: (NSAttributedString * attributedText) {[super setAttributedText:attributedText]; if (attributedText.length) {self.placeholder} = "@"; [self setNeedsDisplay];} / / @end when the application needs with the proxy method UITextView text change #import "ViewController.h" #import "WSTextView.h" @interface ViewController (<); UITextViewDelegate> / / @property (nonatomic, weak) WSTextView *textView; @end @implementation ViewController (void) viewDidLoad {[super viewDidLoad]; Do any additional setup after loading / the view, typically from a nib. (void) {didReceiveMemoryWarning} - [super didReceiveMemoryWarning]; Of any resources that can / Dispose be recreated.} - (void) touchesBegan: (NSSet< UITouch *> touches withEvent: (* *) UIEvent) event *textView alloc] initWithFrame:CGRectMake {WSTextView = [[WSTextView (10, 20, self.view.frame.size.width, 30)]; @ textView.placeholder = "WS"; textView.delegate = self; [self.view addSubview:textView]; / / textView.text = @ "try acting method" does not invoke the text change; / / do not call the text change agent textView.attributedText = [[NSAttributedString alloc] initWithString:@ "rich text"]; / / self.textView = textView;} #pragma mark - UITextViewDelegate - (void) textViewDidChange: (WSTextView * textView) / here trickery, the proxy method parameter types into a custom The WSTextView type, in order to be able to use a custom placeholder property, eliminates the need to give the controller WSTextView type attributes such step. {if (textView.hasText) {/ / textView.text.length textView.placeholder = "else";} {@ @ textView.placeholder = "WS";}} @end

Method five

Through runtime, we find that there is a private member variable named “_placeHolderLabel” within the UITextView. As we all know, Objective-C does not have an absolute private variable, because we can access private variables through KVC.

Features: compared with the above 4 methods, this method is more tricky, although the official did not give us Apple developers to provide similar to the placeholder attribute, but by running, we have private variables in a placeHolderLabel traversal. This method is easy to understand, the amount of code is small, recommend that you use this method.

#import "ViewController.h" #import < objc/runtime.h> #import; < objc/message.h> @interface ViewController (@end @implementation ViewController) - (void) viewDidLoad {[super viewDidLoad]; / / run through, found that UITextView has called a "_placeHolderLabel" int private variables unsigned count = 0; Ivar = *ivars class_copyIvarList ([UITextView class], & count; for (int); I = 0; I < count; i++) {Ivar Ivar = ivars[i]; const = char *name ivar_getName (Ivar); NSString *objcName = [NSString stringWithUTF8String:name]; NSLog (@%d, I, objcName:% @ ");} [self setupTextView];} - {(void) setupTextView UITextView *textView [[UITextView = alloc] initWithFrame:CG RectMake (0, 100, [UIScreen, mainScreen].bounds.size.width, 100]; [textView setBackgroundColor:[UIColor greenColor]]; [self.view addSubview:textView]; UILabel *placeHolderLabel [[UILabel alloc] / / _placeholderLabel = init]; placeHolderLabel.text = @ "please input"; placeHolderLabel.numberOfLines = 0; placeHolderLabel.textColor = [UIColor lightGrayColor]; [placeHolderLabel sizeToFit]; [textView addSubview:placeHolderLabel]; same font textView.font = [UIFont / placeHolderLabel.font = systemFontOfSize:13.f]; [UIFont systemFontOfSize:13.f]; [textView setValue:placeHolderLabel forKey:@ "_placeholderLabel"]}; @end

The VV / wood son (author Jane)
PS: as non specified, all articles are original works, the copyright of the author of all reprint, reproduced please contact the author authorized, and indicate the source, all rewards are all belong to me!

If you are a iOS developer, or interested in this article, please pay attention to me, the follow-up will update more related articles! Coming soon!