美文网首页
iOS-UITextView的占位符

iOS-UITextView的占位符

作者: 志城 | 来源:发表于2017-03-14 17:42 被阅读217次

    头文件

    #import <UIKit/UIKit.h>
    FOUNDATION_EXPORT double UITextView_PlaceholderVersionNumber;
    FOUNDATION_EXPORT const unsigned char UITextView_PlaceholderVersionString[];
    @interface UITextView (Placeholder)
    @property (nonatomic, readonly) UILabel *placeholderLabel;
    @property (nonatomic, strong) IBInspectable NSString *placeholder;
    @property (nonatomic, strong) NSAttributedString *attributedPlaceholder;
    @property (nonatomic, strong) IBInspectable UIColor *placeholderColor;
     +(UIColor *)defaultPlaceholderColor;
    @end
    

    实现文件

    #import "UITextView+Placeholder.h"
    #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 = @" ";
            color = [textField 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);
            
            self.needsUpdateFont = YES;
            [self updatePlaceholderLabel];
            self.needsUpdateFont = NO;
            
            [[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 {
        self.placeholderLabel.text = placeholder;
        [self updatePlaceholderLabel];
    }
    
    - (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 `needsUpdateFont`
    
    - (BOOL)needsUpdateFont {
        return [objc_getAssociatedObject(self, @selector(needsUpdateFont)) boolValue];
    }
    
    - (void)setNeedsUpdateFont:(BOOL)needsUpdate {
        objc_setAssociatedObject(self, @selector(needsUpdateFont), @(needsUpdate), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    
    #pragma mark - KVO
    
    - (void)observeValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary *)change
                           context:(void *)context {
        if ([keyPath isEqualToString:@"font"]) {
            self.needsUpdateFont = (change[NSKeyValueChangeNewKey] != nil);
        }
        [self updatePlaceholderLabel];
    }
    
    
    #pragma mark - Update
    
    - (void)updatePlaceholderLabel {
        if (self.text.length) {
            [self.placeholderLabel removeFromSuperview];
            return;
        }
        
        [self insertSubview:self.placeholderLabel atIndex:0];
        
        if (self.needsUpdateFont) {
            self.placeholderLabel.font = self.font;
            self.needsUpdateFont = NO;
        }
        self.placeholderLabel.textAlignment = self.textAlignment;
        
        // `NSTextContainer` is available since 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
        
        // iOS 6
        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
    

    相关文章

      网友评论

          本文标题:iOS-UITextView的占位符

          本文链接:https://www.haomeiwen.com/subject/lfwhnttx.html