OC常用的UITextView分类封装

UITextView+Extension分类功能:
1、提供占位文字,占位文字颜色、限制字符长度,和右下角提示字符输入数等属性可根据需求进行设置。
2、提供文本内容发生改变时的回调
效果图如下:


image.png

引入UITextView+Extension后,调用示例为:

-(UITextView *)tview{
    if (!_tview) {
        _tview = [[UITextView alloc]initWithFrame:CGRectMake(50, 100, ScreenW-100, 150)];
        _tview.layer.cornerRadius = 5;
        _tview.placeholderStr = @"最多输入10个字";
        _tview.maximumLimit = 10;
        _tview.font = [UIFont systemFontOfSize:15];
        _tview.placeholderColor = UIColor.grayColor;
        _tview.characterLengthPrompt = true;
        _tview.backgroundColor = [UIColor hexColor:@"f5f5f5"];
    }
    return _tview;
}
[self.view addSubview:self.tview];
[self.tview textDidChange:^(NSString *textStr) {
        NSLog(@"正在输入...%@",textStr);
    }];

UITextView+Extension.h代码:

@interface UITextView (Extension)
/**
 *  占位文字
 */
@property (nonatomic, copy) NSString *placeholderStr;

/**
 *  占位文字颜色
 */
@property (nonatomic, strong) UIColor *placeholderColor;

/**
 *  最大显示字符限制(会自动根据该属性截取文本字符长度)
 */
@property (nonatomic, assign) NSInteger maximumLimit;

/**
 *  右下角字符长度提示(需要设置maximumLimit属性),与占位文本颜色、字号一致  默认NO
 */
@property (nonatomic, assign) BOOL characterLengthPrompt;

/**
 *  文本发生改变时回调
 */
- (void)textDidChange:(void(^)(NSString *textStr))handle;

/**
 *  处理系统输入法导致的乱码,如果调用了maximumLimit属性,内部会默认处理乱码
 */
- (void)fixMessyDisplay;
@end

UITextView+Extension.m代码:

#import "UITextView+Extension.h"
#include <objc/runtime.h>
#import "NSString+Extension.h"
@interface UITextView ()

@property (nonatomic, assign) BOOL addNoti;

@property (nonatomic, copy) NSString *lastTextStr;

@property (nonatomic, copy) void(^textHandle) (NSString *textStr);

@end

@implementation UITextView (Extension)

- (void)setAddNoti:(BOOL)addNoti {
    
    objc_setAssociatedObject(self, &@selector(addNoti), [NSNumber numberWithBool:addNoti], OBJC_ASSOCIATION_ASSIGN);
}

- (BOOL)addNoti {
    
    BOOL obj = [objc_getAssociatedObject(self, &@selector(addNoti)) boolValue];
    return obj;
}

- (void)setPlaceholderStr:(NSString *)placeholderStr {
    
    objc_setAssociatedObject(self, &@selector(placeholderStr), placeholderStr, OBJC_ASSOCIATION_COPY_NONATOMIC);
    
    // setNeedsDisplay会在下一个消息循环时刻,调用drawRect:
    [self addTextChangeNoti];
    [self setNeedsDisplay];
}

- (NSString *)placeholderStr {
    
    NSString *obj = objc_getAssociatedObject(self, &@selector(placeholderStr));
    return obj;
}

- (void)setPlaceholderColor:(UIColor *)placeholderColor {
    
    objc_setAssociatedObject(self, &@selector(placeholderColor), placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    // setNeedsDisplay会在下一个消息循环时刻,调用drawRect:
    [self addTextChangeNoti];
}

- (UIColor *)placeholderColor {
    
    UIColor *obj = objc_getAssociatedObject(self, &@selector(placeholderColor));
    return obj;
}

- (void)setMaximumLimit:(NSInteger)maximumLimit {
    
    objc_setAssociatedObject(self, &@selector(maximumLimit), [NSNumber numberWithInteger:maximumLimit], OBJC_ASSOCIATION_ASSIGN);
    
    //setNeedsDisplay会在下一个消息循环时刻,调用drawRect:
    [self addTextChangeNoti];
    [self setNeedsDisplay];
}

- (NSInteger)maximumLimit {
    
    id obj = objc_getAssociatedObject(self, &@selector(maximumLimit));
    return [obj integerValue];
}

- (void)setCharacterLengthPrompt:(BOOL)characterLengthPrompt {
    
    objc_setAssociatedObject(self, &@selector(characterLengthPrompt), [NSNumber numberWithBool:characterLengthPrompt], OBJC_ASSOCIATION_ASSIGN);
    
    //setNeedsDisplay会在下一个消息循环时刻,调用drawRect:
    [self addTextChangeNoti];
    [self setNeedsDisplay];
}

- (BOOL)characterLengthPrompt {
    
    id obj = objc_getAssociatedObject(self, &@selector(characterLengthPrompt));
    return [obj boolValue];
}

- (void)setTextHandle:(void (^)(NSString *))textHandle {
    
    objc_setAssociatedObject(self, &@selector(textHandle), textHandle, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (void (^)(NSString *))textHandle {
    
    id handle = objc_getAssociatedObject(self, &@selector(textHandle));
    if (handle) {
        
        return (void(^)(NSString *textStr))handle;
    }
    return nil;
}

- (void)setLastTextStr:(NSString *)lastTextStr {
    
    objc_setAssociatedObject(self, @selector(lastTextStr), lastTextStr, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)lastTextStr {
    
    return [NSString emptyStr:objc_getAssociatedObject(self, _cmd)];
}

- (void)textDidChange:(void (^)(NSString *))handle {
    
    self.textHandle = handle;
    [self addTextChangeNoti];
}

- (void)fixMessyDisplay {
    
    if(self.maximumLimit <= 0) {self.maximumLimit = MAXFLOAT;}
    [self addTextChangeNoti];
}

/**
 *  监听文字改变
 */
- (void)textDidChange {
    
    //重绘
    [self characterTruncation];
    [self setNeedsDisplay];
}

- (void)setFont:(UIFont *)font {
    
    // setNeedsDisplay会在下一个消息循环时刻,调用drawRect:
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    
    //设置文字属性
    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
    attributes[NSFontAttributeName] = self.font;
    attributes[NSForegroundColorAttributeName] = self.placeholderColor ? self.placeholderColor : [UIColor lightGrayColor];
    
    CGFloat x = 5;
    CGFloat y = 8;
    CGFloat width = rect.size.width -2 * x;
    
    //画最大字符文本,添加文本显示边界
    if((self.maximumLimit > 0) && (self.characterLengthPrompt == YES)) {
        
        [self setContentInset:UIEdgeInsetsMake(0, 0, 25, 0)];
        
        NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
        paragraphStyle.alignment = NSTextAlignmentRight;
        
        NSMutableDictionary *maximumLimitAttributes = [attributes mutableCopy];
        maximumLimitAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
        
        NSString *limitStr = [NSString stringWithFormat:@"%lu/%ld",(unsigned long)self.text.length > (long)self.maximumLimit ? (long)self.maximumLimit : (unsigned long)self.text.length ,(long)self.maximumLimit];
        
        [limitStr drawInRect:CGRectMake(x, rect.size.height-20+self.contentOffset.y, width, 20) withAttributes:maximumLimitAttributes];
    }
    //如果不需要显示最大字符限制文本,则把边界置为默认
    else {
        
        [self setContentInset:UIEdgeInsetsZero];
    }
    
    // 如果有输入文字,就直接返回,不画占位文字
    if (self.hasText) return;
    
    //画文字
    CGFloat height = rect.size.height - 2 * y;
    CGRect placeholderRect = CGRectMake(x, y, width, height);
    [self.placeholderStr drawInRect:placeholderRect withAttributes:attributes];
}

- (void)characterTruncation {
    
    //字符截取
    if(self.maximumLimit) {
        
        UITextRange *selectedRange = [self markedTextRange];
        //获取高亮部分
        UITextPosition *position = [self positionFromPosition:selectedRange.start offset:0];
        //没有高亮选择的字,则对已输入的文字进行字数统计和限制,如果有高亮待选择的字,则暂不对文字进行统计和限制
        if ((position == nil) && (self.text.length > self.maximumLimit)) {
            
            const char *res = [self.text substringToIndex:self.maximumLimit].UTF8String;
            if (res == NULL) {
                self.text = [self.text substringToIndex:self.maximumLimit - 1];
            }else{
                self.text = [self.text substringToIndex:self.maximumLimit];
            }
        }
    }
    
    if((self.textHandle) && (![self.text isEqualToString:self.lastTextStr])) {
        
        self.textHandle(self.text);
    }
    self.lastTextStr = self.text;
}

- (void)addTextChangeNoti {
    
    if(self.addNoti == NO) {
        
        // 当UITextView的文字发生改变时,UITextView自己会发出一个UITextViewTextDidChangeNotification通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange) name:UITextViewTextDidChangeNotification object:nil];
    }
    self.addNoti = YES;
}

- (void)dealloc {
    
    if(self.addNoti == YES) {
        
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:nil];
    }
}
@end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容