IOS development – UITextView implementation with Placeholder

When I was in the industry, I wanted to add Placeholder to the UITextView, which made it difficult for me to do so. Then, I looked at other people’s blogs and simplified books to find out the answers. But the implementation is barely satisfactory. Later, it was found that the packaged class clusters were very convenient to use. Recently, a lot of novice also encountered such a problem, through my previous blog on other people’s mailbox, always find my QQ, ask me how to solve. I think it’s better to put him on the internet.

UITextView+Placeholder.h

IOS development - UITextView implementation with Placeholder
screen snapshot 2016-11-14 a.m. 10.35.51.png

UITextView+Placeholder.m

Import < objc/runtime.h>

Import “UITextView+Placeholder.h””

@implementation UITextView (Placeholder)

Pragma mark – Swizzle Dealloc

  • (void) load
    is this the {/ / best solution?
    method_exchangeImplementations (class_getInstanceMethod (self.class, NSSelectorFromString (@ dealloc), class_getInstanceMethod (self.class), @selector (swizzledDealloc)));}
  • (void) swizzledDealloc [[NSNotificationCenter defaultCenter] {
    removeObserver:self];
    UILabel *label = objc_getAssociatedObject (self, @selector (placeholderLabel));
    if (label) {for (NSString * key in self.class.observingKeys @try [self removeObserver:self) {{forKeyPath:key]}; @catch (NSException *exception) {}}} / / Do nothing
    [self swizzledDealloc]
    ;}

Pragma mark – Class Methods

Pragma mark defaultPlaceholderColor

  • (UIColor) defaultPlaceholderColor
    static UIColor color {
    = nil; static dispatch_once_t onceToken;
    dispatch_once (& onceToken, UITextField *textField [[UITextField alloc] ^{= init]; textField.placeholder = [textField; color = “@” valueForKeyPath:@ “_placeholderLabel.textColor”];});
    return color;
    }

Pragma mark – observingKeys

  • (NSArray * observingKeys) {
    return @[@ “attributedText”, “bounds”, @ @ @ “font”, “frame”, “text”, @ @ @ “textAlignment”, “textContainerInset”];}

Pragma mark – Properties

Pragma mark placeholderLabel

  • (UILabel) placeholderLabel UILabel label {
    = objc_getAssociatedObject (self, @selector (placeholderLabel));
    (if! Label) {NSAttributedString *originalText = self.attributedText; self.text = “@”; / / lazily set font of `UITextView`. self.attributedText = originalText; label = [[UILabel alloc] init]; label.textColor [self.class = defaultPlaceholderColor]; label.numberOfLines = 0; label.userInteractionEnabled = NO; objc_setAssociatedObject (self, @selector (placeholderLabel), label, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (updatePlaceholderLabel) Name:UITextViewTextDidChangeNotification object:self]; for (NSString *key in self.class.observingKeys [self addObserver:self forKeyPath:key options:NSKeyValueObservingOptionNew) {context:nil]}};
    return label;
    }

Pragma mark placeholder

  • (NSString *) placeholder {
    , return, self.placeholderLabel.text,
    }
  • (void) setPlaceholder: (NSString *) placeholder {
    = placeholder;
    [self updatePlaceholderLabel];
    } self.placeholderLabel.text
  • (NSAttributedString *) attributedPlaceholder {
    , return, self.placeholderLabel.attributedText,
    }
  • (void) setAttributedPlaceholder: (NSAttributedString * attributedPlaceholder) {
    self.placeholderLabel.attributedText = attributedPlaceholder
    ; [self updatePlaceholderLabel]
    ;}

Pragma mark placeholderColor

  • (UIColor *) placeholderColor {
    , return, self.placeholderLabel.textColor,
    }
  • (void) setPlaceholderColor: (UIColor *) placeholderColor {
    self.placeholderLabel.textColor = placeholderColor;
    }

Pragma mark – KVO

  • (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (ID) object change: (NSDictionary * Change) context: (void * context) {[self updatePlaceholderLabel]
    };

Pragma mark – Update

  • (void) updatePlaceholderLabel
    if (self.text.length) {{return}; [self.placeholderLabel removeFromSuperview]; [self insertSubview:self.placeholderLabel atIndex:0]; self.placeholderLabel.font = self.font;
    = self.placeholderLabel.textAlignment self.textAlignment; is available since / / NSTextContainer iOS 7
    CGFloat lineFragmentPadding;
    UIEdgeInsets textContainerInset;

Pragma deploymate push “ignored-api-availability””

IOS 7+ if (NSFoundationVersionNumber / > NSFoundationVersionNumber_iOS_6_1) {lineFragmentPadding = self.textContainer.lineFragmentPadding; textContainerInset = self.textContainerInset;}

Pragma deploymate pop

6 / / iOS else {lineFragmentPadding = 5; textContainerInset = UIEdgeInsetsMake (8, 0, 8, 0);} CGFloat x = lineFragmentPadding + textContainerInset.left; CGFloat y = textContainerInset.top; CGFloat = width CGRectGetWidth (self.bounds) - X - lineFragmentPadding - textContainerInset.right; CGFloat height = [self.placeholderLabel sizeThatFits:CGSizeMake (width, 0)].height; self.placeholderLabel.frame = CGRectMake (x, y, width, height);

}

@end

In iOS, UITextField comes with the PlaceHolder attribute, which makes it handy for prompt input. However, a UITextView control that can also enter text does not have the PlaceHolder attribute, but it is somewhat inconvenient.
usage: the introduction of files into the project, and then directly with the property placeHolder, you can achieve the effect.

The core idea is to use 2 UITextView to simulate the effect of PlaceHolder, which is the input of TextView in the area of the surface, the background should be set to transparent, as the role of PlaceHolder TextView in the bottom two by UITextViewDelegate dynamic control.