123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- //
- // PlaceholderTextView.m
- // StocksBar
- //
- // Created by 翟玉磊 on 2017/3/2.
- // Copyright © 2017年 翟玉磊. All rights reserved.
- //
- #import "PlaceholderTextView.h"
- #define HAS_TEXT_CONTAINER [self respondsToSelector:@selector(textContainer)]
- #define HAS_TEXT_CONTAINER_INSETS(x) [(x) respondsToSelector:@selector(textContainerInset)]
- @interface PlaceholderTextView ()
- @property (strong, nonatomic) UITextView *_placeholderTextView;
- @end
- static NSString * const kAttributedPlaceholderKey = @"attributedPlaceholder";
- static NSString * const kPlaceholderKey = @"placeholder";
- static NSString * const kFontKey = @"font";
- static NSString * const kAttributedTextKey = @"attributedText";
- static NSString * const kTextKey = @"text";
- static NSString * const kExclusionPathsKey = @"exclusionPaths";
- static NSString * const kLineFragmentPaddingKey = @"lineFragmentPadding";
- static NSString * const kTextContainerInsetKey = @"textContainerInset";
- static NSString * const kTextAlignmentKey = @"textAlignment";
- @implementation PlaceholderTextView
- - (instancetype)initWithCoder:(NSCoder *)coder
- {
- self = [super initWithCoder:coder];
- if (self) {
- [self preparePlaceholder];
- }
- return self;
- }
- #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- - (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer
- {
- self = [super initWithFrame:frame textContainer:textContainer];
- if (self) {
- [self preparePlaceholder];
- }
- return self;
- }
- #else
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self preparePlaceholder];
- }
- return self;
- }
- #endif
- - (void)preparePlaceholder
- {
- NSAssert(!self._placeholderTextView, @"placeholder has been prepared already: %@", self._placeholderTextView);
- // the label which displays the placeholder
- // needs to inherit some properties from its parent text view
-
- // account for standard UITextViewPadding
-
- CGRect frame = self.bounds;
- self._placeholderTextView = [[UITextView alloc] initWithFrame:frame];
- self._placeholderTextView.opaque = NO;
- self._placeholderTextView.backgroundColor = [UIColor clearColor];
- self._placeholderTextView.textColor = [UIColor colorWithWhite:0.7f alpha:0.7f];
- self._placeholderTextView.textAlignment = self.textAlignment;
- self._placeholderTextView.editable = NO;
- self._placeholderTextView.scrollEnabled = NO;
- self._placeholderTextView.userInteractionEnabled = NO;
- self._placeholderTextView.font = self.font;
- self._placeholderTextView.isAccessibilityElement = NO;
- self._placeholderTextView.contentOffset = self.contentOffset;
- self._placeholderTextView.contentInset = self.contentInset;
-
- if ([self._placeholderTextView respondsToSelector:@selector(setSelectable:)]) {
- self._placeholderTextView.selectable = NO;
- }
-
- if (HAS_TEXT_CONTAINER) {
- self._placeholderTextView.textContainer.exclusionPaths = self.textContainer.exclusionPaths;
- self._placeholderTextView.textContainer.lineFragmentPadding = self.textContainer.lineFragmentPadding;
- }
-
- if (HAS_TEXT_CONTAINER_INSETS(self)) {
- self._placeholderTextView.textContainerInset = self.textContainerInset;
- }
-
- if (_attributedPlaceholder) {
- self._placeholderTextView.attributedText = _attributedPlaceholder;
- } else if (_placeholder) {
- self._placeholderTextView.text = _placeholder;
- }
-
- [self setPlaceholderVisibleForText:self.text];
-
- self.clipsToBounds = YES;
-
- // some observations
- NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:self selector:@selector(textDidChange:)
- name:UITextViewTextDidChangeNotification object:self];
-
- [self addObserver:self forKeyPath:kAttributedPlaceholderKey
- options:NSKeyValueObservingOptionNew context:nil];
- [self addObserver:self forKeyPath:kPlaceholderKey
- options:NSKeyValueObservingOptionNew context:nil];
- [self addObserver:self forKeyPath:kFontKey
- options:NSKeyValueObservingOptionNew context:nil];
- [self addObserver:self forKeyPath:kAttributedTextKey
- options:NSKeyValueObservingOptionNew context:nil];
- [self addObserver:self forKeyPath:kTextKey
- options:NSKeyValueObservingOptionNew context:nil];
- [self addObserver:self forKeyPath:kTextAlignmentKey
- options:NSKeyValueObservingOptionNew context:nil];
-
- if (HAS_TEXT_CONTAINER) {
- [self.textContainer addObserver:self forKeyPath:kExclusionPathsKey
- options:NSKeyValueObservingOptionNew context:nil];
- [self.textContainer addObserver:self forKeyPath:kLineFragmentPaddingKey
- options:NSKeyValueObservingOptionNew context:nil];
- }
-
- if (HAS_TEXT_CONTAINER_INSETS(self)) {
- [self addObserver:self forKeyPath:kTextContainerInsetKey
- options:NSKeyValueObservingOptionNew context:nil];
- }
- }
- - (void)setPlaceholder:(NSString *)placeholderText
- {
- _placeholder = [placeholderText copy];
- _attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholderText];
-
- [self resizePlaceholderFrame];
- }
- - (void)setAttributedPlaceholder:(NSAttributedString *)attributedPlaceholderText
- {
- _placeholder = attributedPlaceholderText.string;
- _attributedPlaceholder = [attributedPlaceholderText copy];
-
- [self resizePlaceholderFrame];
- }
- - (void)layoutSubviews
- {
- [super layoutSubviews];
- [self resizePlaceholderFrame];
- }
- - (void)resizePlaceholderFrame
- {
- CGRect frame = self._placeholderTextView.frame;
- frame.size = self.bounds.size;
- self._placeholderTextView.frame = frame;
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
- change:(NSDictionary *)change context:(void *)context
- {
- if ([keyPath isEqualToString:kAttributedPlaceholderKey]) {
- self._placeholderTextView.attributedText = [change valueForKey:NSKeyValueChangeNewKey];
- }
- else if ([keyPath isEqualToString:kPlaceholderKey]) {
- self._placeholderTextView.text = [change valueForKey:NSKeyValueChangeNewKey];
- }
- else if ([keyPath isEqualToString:kFontKey]) {
- self._placeholderTextView.font = [change valueForKey:NSKeyValueChangeNewKey];
- }
- else if ([keyPath isEqualToString:kAttributedTextKey]) {
- NSAttributedString *newAttributedText = [change valueForKey:NSKeyValueChangeNewKey];
- [self setPlaceholderVisibleForText:newAttributedText.string];
- }
- else if ([keyPath isEqualToString:kTextKey]) {
- NSString *newText = [change valueForKey:NSKeyValueChangeNewKey];
- [self setPlaceholderVisibleForText:newText];
- }
- else if ([keyPath isEqualToString:kExclusionPathsKey]) {
- self._placeholderTextView.textContainer.exclusionPaths = [change objectForKey:NSKeyValueChangeNewKey];
- [self resizePlaceholderFrame];
- }
- else if ([keyPath isEqualToString:kLineFragmentPaddingKey]) {
- self._placeholderTextView.textContainer.lineFragmentPadding = [[change objectForKey:NSKeyValueChangeNewKey] floatValue];
- [self resizePlaceholderFrame];
- }
- else if ([keyPath isEqualToString:kTextContainerInsetKey]) {
- NSValue *value = [change objectForKey:NSKeyValueChangeNewKey];
- self._placeholderTextView.textContainerInset = value.UIEdgeInsetsValue;
- }
- else if ([keyPath isEqualToString:kTextAlignmentKey]) {
- NSNumber *alignment = [change objectForKey:NSKeyValueChangeNewKey];
- self._placeholderTextView.textAlignment = alignment.intValue;
- }
- else {
- [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
- }
- }
- - (void)setPlaceholderTextColor:(UIColor *)placeholderTextColor
- {
- self._placeholderTextView.textColor = placeholderTextColor;
- }
- - (UIColor *)placeholderTextColor
- {
- return self._placeholderTextView.textColor;
- }
- - (void)textDidChange:(NSNotification *)aNotification
- {
- [self setPlaceholderVisibleForText:self.text];
- }
- - (BOOL)becomeFirstResponder
- {
- [self setPlaceholderVisibleForText:self.text];
-
- return [super becomeFirstResponder];
- }
- - (void)setPlaceholderVisibleForText:(NSString *)text
- {
-
- if (text.length < 1) {
- if (self.fadeTime > 0.0) {
- if (![self._placeholderTextView isDescendantOfView:self]) {
- self._placeholderTextView.alpha = 0;
- [self addSubview:self._placeholderTextView];
- [self sendSubviewToBack:self._placeholderTextView];
- }
- [UIView animateWithDuration:_fadeTime animations:^{
- self._placeholderTextView.alpha = 1;
- }];
- }
- else {
- [self addSubview:self._placeholderTextView];
- [self sendSubviewToBack:self._placeholderTextView];
- self._placeholderTextView.alpha = 1;
- }
- }
- else {
- if (self.fadeTime > 0.0) {
- [UIView animateWithDuration:_fadeTime animations:^{
- self._placeholderTextView.alpha = 0;
- }];
- }
- else {
- [self._placeholderTextView removeFromSuperview];
- }
- }
- }
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [self removeObserver:self forKeyPath:kAttributedPlaceholderKey];
- [self removeObserver:self forKeyPath:kPlaceholderKey];
- [self removeObserver:self forKeyPath:kFontKey];
- [self removeObserver:self forKeyPath:kAttributedTextKey];
- [self removeObserver:self forKeyPath:kTextKey];
- [self removeObserver:self forKeyPath:kTextAlignmentKey];
-
- if (HAS_TEXT_CONTAINER) {
- [self.textContainer removeObserver:self forKeyPath:kExclusionPathsKey];
- [self.textContainer removeObserver:self forKeyPath:kLineFragmentPaddingKey];
- }
-
- if (HAS_TEXT_CONTAINER_INSETS(self)) {
- [self removeObserver:self forKeyPath:kTextContainerInsetKey];
- }
- }
- @end
|