Initial commit
This commit is contained in:
+78
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// UMComEditTextView.h
|
||||
// UMCommunity
|
||||
//
|
||||
// Created by umeng on 15/11/11.
|
||||
// Copyright © 2015年 Umeng. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class UMComEditTextView;
|
||||
|
||||
@protocol UMComEditTextViewDelegate <NSObject>
|
||||
|
||||
@optional;
|
||||
- (NSArray *)editTextViewDidUpdate:(UMComEditTextView *)textView matchWords:(NSArray *)matchWords;
|
||||
|
||||
- (BOOL)editTextView:(UMComEditTextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text complection:(void (^)())block;
|
||||
|
||||
- (void)editTextViewDidChangeSelection:(UMComEditTextView *)textView;
|
||||
|
||||
- (void)editTextViewDidEndEditing:(UMComEditTextView *)textView;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface UMComEditTextView : UITextView
|
||||
|
||||
@property (nonatomic, weak) id<UMComEditTextViewDelegate> editDelegate;
|
||||
|
||||
@property (nonatomic, strong) NSArray *checkWords;
|
||||
|
||||
@property (nonatomic, assign) CGFloat maxTextLenght;
|
||||
|
||||
@property (nonatomic, strong) UILabel *placeholderLabel;
|
||||
|
||||
@property (nonatomic, copy) NSArray * (^getCheckWords)();
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame checkWords:(NSArray *)checkWords regularExStrArray:(NSArray *)regularExStrArray;
|
||||
|
||||
- (void)updateEditTextView;
|
||||
|
||||
- (NSInteger)getRealTextLength;
|
||||
|
||||
//判断text是否大于当前控件的最大限制
|
||||
-(BOOL)checkMaxLength:(NSString*)text;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface UMComHighLightTextUnit : UIResponder
|
||||
/**
|
||||
* 文本单元内容
|
||||
*/
|
||||
@property (nonatomic,copy ) NSString *text;
|
||||
|
||||
/**
|
||||
* 文本单元字体
|
||||
*/
|
||||
@property (nonatomic,strong) UIFont *font;
|
||||
|
||||
/**
|
||||
* 文本单元颜色
|
||||
*/
|
||||
@property (nonatomic,strong) UIColor *textColor;
|
||||
|
||||
/**
|
||||
* 文本单元在字符串中的位置
|
||||
*/
|
||||
@property (nonatomic,assign) NSRange range;
|
||||
|
||||
+ (UMComHighLightTextUnit *)textUnitWithText:(NSString *)text
|
||||
font:(UIFont *)font
|
||||
textColor:(UIColor *)color
|
||||
range:(NSRange)range;
|
||||
|
||||
@end
|
||||
+421
@@ -0,0 +1,421 @@
|
||||
//
|
||||
// UMComEditTextView.m
|
||||
// UMCommunity
|
||||
//
|
||||
// Created by umeng on 15/11/11.
|
||||
// Copyright © 2015年 Umeng. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UMComEditTextView.h"
|
||||
#import "UMComResouceDefines.h"
|
||||
#import <UMComFoundation/UMUtils.h>
|
||||
#import "UMComMutiTextRun.h"
|
||||
#import <UMComFoundation/UMComKit+String.h>
|
||||
#import <UMComFoundation/UMComKit+Color.h>
|
||||
|
||||
@interface UMComEditTextView () <UITextViewDelegate>
|
||||
|
||||
@property (nonatomic, strong) UILabel *noticeLabel;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *regularExpressionArray;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UMComEditTextView
|
||||
{
|
||||
BOOL isShowTopicNoticeBgView;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [self initWithFrame:frame checkWords:nil regularExStrArray:nil];
|
||||
if (self) {
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame checkWords:(NSArray *)checkWords regularExStrArray:(NSArray *)regularExStrArray
|
||||
{
|
||||
if (UMSYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) {
|
||||
|
||||
NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(frame.size.width, frame.size.height)];
|
||||
container.lineFragmentPadding = 2;
|
||||
container.size = CGSizeMake(self.frame.size.width, MAXFLOAT);//设置成最大得高度输入多文本滚动
|
||||
container.widthTracksTextView = YES;
|
||||
NSTextStorage *textStorage = [[NSTextStorage alloc]init];
|
||||
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
|
||||
[layoutManager addTextContainer:container];
|
||||
[textStorage addLayoutManager:layoutManager];
|
||||
self = [super initWithFrame:frame textContainer:container];
|
||||
//如果有话题则默认添加话题
|
||||
}else{
|
||||
self = [super initWithFrame:frame];
|
||||
}
|
||||
if (self) {
|
||||
_regularExpressionArray = [NSMutableArray arrayWithCapacity:regularExStrArray.count];
|
||||
for (NSString *regex in regularExStrArray) {
|
||||
NSRegularExpression *regularExpression = [NSRegularExpression
|
||||
regularExpressionWithPattern:regex
|
||||
options:NSRegularExpressionCaseInsensitive
|
||||
error:nil];
|
||||
if (regularExpression) {
|
||||
[_regularExpressionArray addObject:regularExpression];
|
||||
}
|
||||
}
|
||||
self.textColor= [UIColor blackColor];
|
||||
self.font = [UIFont systemFontOfSize:20];
|
||||
self.delegate = self;
|
||||
self.checkWords = checkWords;
|
||||
_noticeLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
|
||||
//_noticeLabel.backgroundColor = [UIColor clearColor];
|
||||
_noticeLabel.font = UMComFontNotoSansLightWithSafeSize(14);
|
||||
_noticeLabel.text = UMComLocalizedString(@"um_com_contentTooLong", @"抱歉,内容过长");
|
||||
_noticeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_noticeLabel.textColor = [UIColor blueColor];
|
||||
_noticeLabel.backgroundColor = [UIColor lightGrayColor];
|
||||
_noticeLabel.hidden = YES;
|
||||
[self addSubview:_noticeLabel];
|
||||
_placeholderLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, -5, frame.size.width, 40)];
|
||||
_placeholderLabel.font = UMComFontNotoSansLightWithSafeSize(15);
|
||||
_placeholderLabel.backgroundColor = [UIColor clearColor];
|
||||
_placeholderLabel.textColor = [UIColor grayColor];
|
||||
[self addSubview:_placeholderLabel];
|
||||
|
||||
_maxTextLenght = 1000;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateEditTextView
|
||||
{
|
||||
[self textViewDidChange:self];
|
||||
[self matchWordsWithTextColor:UMComColorWithHexString(FontColorBlue)];
|
||||
}
|
||||
|
||||
#pragma mark - UITextViewDelegate
|
||||
|
||||
- (void)textViewDidChangeSelection:(UITextView *)textView
|
||||
{
|
||||
[self showPlaceHolderLabelWithTextView:textView];
|
||||
if (self.editDelegate && [self.editDelegate respondsToSelector:@selector(editTextViewDidChangeSelection:)]) {
|
||||
[self.editDelegate editTextViewDidChangeSelection:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
|
||||
{
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)showPlaceHolderLabelWithTextView:(UITextView *)textView
|
||||
{
|
||||
if (textView.text.length > 0 && ![@" " isEqualToString:textView.text]) {
|
||||
self.placeholderLabel.hidden = YES;
|
||||
}else{
|
||||
self.placeholderLabel.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)textViewDidEndEditing:(UITextView *)textView
|
||||
{
|
||||
if (textView.text.length == 0) {
|
||||
self.placeholderLabel.hidden = NO;
|
||||
}
|
||||
if (UMSYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@"6")) {
|
||||
[self matchWordsWithTextColor:UMComColorWithHexString(FontColorBlue)];
|
||||
}
|
||||
if (self.editDelegate && [self.editDelegate respondsToSelector:@selector(editTextViewDidEndEditing:)]) {
|
||||
[self.editDelegate editTextViewDidEndEditing:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hiddenTextView
|
||||
{
|
||||
self.noticeLabel.hidden = YES;
|
||||
}
|
||||
|
||||
-(void) doShowPlaceHolderLabel
|
||||
{
|
||||
self.noticeLabel.hidden = NO;
|
||||
//显示noticeLabel的位置
|
||||
self.noticeLabel.frame = CGRectMake(self.contentOffset.x,self.contentOffset.y, self.bounds.size.width, self.bounds.size.height);
|
||||
[self performSelector:@selector(hiddenTextView) withObject:nil afterDelay:0.8f];
|
||||
}
|
||||
|
||||
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
|
||||
{
|
||||
//判断text的长度大于零,避免删除的情况不能编辑
|
||||
//if ([self getRealTextLength] > self.maxTextLenght && text.length > 0) {
|
||||
if (self.maxTextLenght <= 0) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
//当时删除的时候text为空,以此方法判断是否用户点击删除按键
|
||||
if ([text isEqualToString:@""]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSInteger markLength = 0;//标记的长度
|
||||
UITextRange* curMarkText = textView.markedTextRange;
|
||||
if (curMarkText) {
|
||||
markLength = [self offsetFromPosition:curMarkText.start toPosition:curMarkText.end];
|
||||
}
|
||||
|
||||
NSInteger curLength = 0.f;
|
||||
NSInteger nextLength = 0.f;
|
||||
curLength = [UMComKit getStringLengthWithString:self.text];//当前长度(用于判断表情)
|
||||
nextLength = [UMComKit getStringLengthWithString:text];//即将要输入的长度(用于判断表情)
|
||||
curLength -= markLength;
|
||||
if (curLength + nextLength > self.maxTextLenght ) {
|
||||
self.noticeLabel.hidden = NO;
|
||||
//显示noticeLabel的位置
|
||||
self.noticeLabel.frame = CGRectMake(self.contentOffset.x,self.contentOffset.y, self.bounds.size.width, self.bounds.size.height);
|
||||
[self performSelector:@selector(hiddenTextView) withObject:nil afterDelay:0.8f];
|
||||
return NO;
|
||||
}else{
|
||||
self.noticeLabel.hidden = YES;
|
||||
}
|
||||
if (self.editDelegate && [self.editDelegate respondsToSelector:@selector(editTextView:shouldChangeTextInRange:replacementText:complection:)]) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
return [self.editDelegate editTextView:self shouldChangeTextInRange:range replacementText:text complection:^{
|
||||
[weakSelf textViewDidChange:weakSelf];
|
||||
|
||||
}];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)textViewDidChange:(UITextView *)textView
|
||||
{
|
||||
if (UMSYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) {
|
||||
[self matchWordsWithTextColor:UMComColorWithHexString(FontColorBlue)];
|
||||
}
|
||||
[self showPlaceHolderLabelWithTextView:textView];
|
||||
|
||||
|
||||
//http://stackoverflow.com/questions/19948394/textviewdidchange-crashes-in-ios-7
|
||||
if (textView.markedTextRange) {
|
||||
//联想输入的时候,不需要计算其长度
|
||||
return;
|
||||
}
|
||||
|
||||
//此处判断是否达到最大长度限制
|
||||
NSInteger curLength = [UMComKit getStringLengthWithString:self.text];//当前长度(用于判断表情)
|
||||
if (curLength > self.maxTextLenght && self.maxTextLenght > 0) {
|
||||
[self doShowPlaceHolderLabel];
|
||||
self.text = [self.text substringToIndex:self.maxTextLenght];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - textUpdata
|
||||
|
||||
- (void)matchWordsWithTextColor:(UIColor *)color
|
||||
{
|
||||
if (self.text.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (self.getCheckWords) {
|
||||
self.checkWords = self.getCheckWords();
|
||||
}
|
||||
__weak typeof(self) weakSelf = self;
|
||||
if (UMSYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) {
|
||||
[self updateiOS7AndLaterTextWithColor:color checkWords:self.checkWords completion:^(NSArray *matchWords) {
|
||||
if (weakSelf.editDelegate && [weakSelf.editDelegate respondsToSelector:@selector(editTextViewDidUpdate:matchWords:)]) {
|
||||
weakSelf.checkWords = [weakSelf.editDelegate editTextViewDidUpdate:weakSelf matchWords:[matchWords valueForKeyPath:@"text"]];
|
||||
}
|
||||
}];
|
||||
}else{
|
||||
[self creatHighLightWithFont:self.font color:color checkWords:self.checkWords complection:^(NSArray * matchWords, NSMutableAttributedString *attributedString) {
|
||||
if (self.editDelegate && [self.editDelegate respondsToSelector:@selector(editTextViewDidUpdate:matchWords:)]) {
|
||||
[self.editDelegate editTextViewDidUpdate:weakSelf matchWords:[matchWords valueForKeyPath:@"text"]];
|
||||
}
|
||||
weakSelf.attributedText = attributedString;
|
||||
}];
|
||||
}
|
||||
[self reloadInputViews];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *)rangeArrayOfSubString:(NSString *)subString originStrin:(NSString *)originString lastRangeArray:(NSArray *)lastRangeArray
|
||||
{
|
||||
if (originString.length >= subString.length) {
|
||||
NSMutableArray *rangeArray = [NSMutableArray array];
|
||||
|
||||
if (lastRangeArray.count > 0) {
|
||||
[rangeArray addObjectsFromArray:lastRangeArray];
|
||||
}
|
||||
NSRange macthRange = [originString rangeOfString:subString];
|
||||
if (macthRange.length > 0) {
|
||||
NSValue *rangeValue = [NSValue valueWithRange:macthRange];
|
||||
[rangeArray addObject:rangeValue];
|
||||
[self rangeArrayOfSubString:subString originStrin:[originString substringFromIndex:macthRange.length - 1] lastRangeArray:rangeArray];
|
||||
}
|
||||
return rangeArray;
|
||||
}
|
||||
|
||||
return lastRangeArray;
|
||||
}
|
||||
|
||||
- (void)updateiOS7AndLaterTextWithColor:(UIColor *)color
|
||||
checkWords:(NSArray *)checkWords
|
||||
completion:(void (^) (NSArray *matchWords))block
|
||||
{
|
||||
[self.textStorage addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, self.textStorage.length)];
|
||||
NSMutableArray *HLTextUnits = [NSMutableArray array];
|
||||
|
||||
for (NSString *checkWord in checkWords) {
|
||||
NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:checkWord options:NSRegularExpressionDotMatchesLineSeparators error:nil];
|
||||
NSArray *matchs = [regular matchesInString:self.textStorage.string
|
||||
options:0
|
||||
range:NSMakeRange(0, [self.textStorage.string length])];
|
||||
for (NSTextCheckingResult *match in matchs) {
|
||||
[self.textStorage addAttribute:NSForegroundColorAttributeName value:color range:match.range];
|
||||
if (![[HLTextUnits valueForKeyPath:@"text"] containsObject:checkWord]) {
|
||||
UMComHighLightTextUnit *textUnit = [UMComHighLightTextUnit textUnitWithText:checkWord font:self.font textColor:color range:match.range];
|
||||
[HLTextUnits addObject:textUnit];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (block) {
|
||||
block(HLTextUnits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//产生高亮字体
|
||||
- (void)creatHighLightWithFont:(UIFont *)font color:(UIColor *)color checkWords:(NSArray *)checkWords complection:(void(^)(NSArray *checkWords ,NSMutableAttributedString *attributedString))block
|
||||
{
|
||||
if (self.text.length == 0) {
|
||||
return;
|
||||
}
|
||||
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:self.text];
|
||||
self.attributedText = attributedString;
|
||||
[attributedString addAttribute:NSForegroundColorAttributeName value:(id)[UIColor blackColor] range:NSMakeRange(0, attributedString.length-1)];
|
||||
|
||||
NSString *string = attributedString.string;
|
||||
NSMutableArray *HLTextUnits = [NSMutableArray array];
|
||||
for (NSRegularExpression *regularExpression in _regularExpressionArray) {
|
||||
NSArray *matchs = [regularExpression matchesInString:string options:0 range:NSMakeRange(0, string.length)];
|
||||
if ([regularExpression.pattern isEqualToString:UrlRelerSring]) {
|
||||
for (NSTextCheckingResult *match in matchs)
|
||||
{
|
||||
NSString* matchText = [self.textStorage.string substringWithRange:match.range];
|
||||
[attributedString addAttribute:(id)NSForegroundColorAttributeName value:(id)color range:match.range];
|
||||
if (![[HLTextUnits valueForKeyPath:@"text"] containsObject:matchText]) {
|
||||
UMComHighLightTextUnit *textUnit = [UMComHighLightTextUnit textUnitWithText:matchText font:self.font textColor:color range:match.range];
|
||||
[HLTextUnits addObject:textUnit];
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for (NSTextCheckingResult *match in matchs)
|
||||
{
|
||||
NSRange matchRange = NSMakeRange(match.range.location, match.range.length);
|
||||
NSString *matchText = [string substringWithRange:matchRange];
|
||||
|
||||
for (NSString *checkWord in checkWords) {
|
||||
if ([matchText isEqualToString:checkWord]) {
|
||||
[attributedString addAttribute:(id)NSForegroundColorAttributeName value:(id)color range:match.range];
|
||||
if (![[HLTextUnits valueForKeyPath:@"text"] containsObject:matchText]) {
|
||||
UMComHighLightTextUnit *textUnit = [UMComHighLightTextUnit textUnitWithText:matchText font:self.font textColor:color range:match.range];
|
||||
[HLTextUnits addObject:textUnit];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[attributedString addAttribute:NSFontAttributeName value:(id)font range:NSMakeRange(0, attributedString.length)];
|
||||
if (block) {
|
||||
block(HLTextUnits, attributedString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)getRealTextLength
|
||||
{
|
||||
NSInteger topicAndUserLength = 0;
|
||||
NSMutableArray *matchs = [NSMutableArray array];
|
||||
for (NSRegularExpression *regularExpression in _regularExpressionArray) {
|
||||
NSArray *subMatchs = [regularExpression matchesInString:self.text options:0 range:NSMakeRange(0, self.text.length)];
|
||||
if (subMatchs.count > 0) {
|
||||
[matchs addObjectsFromArray:subMatchs];
|
||||
}
|
||||
}
|
||||
NSArray *checkWords = self.checkWords;
|
||||
for (NSTextCheckingResult *match in matchs)
|
||||
{
|
||||
for (NSString *item in checkWords) {
|
||||
NSRange matchRange = NSMakeRange(match.range.location, match.range.length);
|
||||
NSString *matchText = [self.text substringWithRange:matchRange];
|
||||
if ([item isEqualToString:matchText]) {
|
||||
topicAndUserLength += [UMComKit getStringLengthWithString:matchText];
|
||||
}
|
||||
}
|
||||
}
|
||||
NSString *realTextString = [self.text stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
NSInteger realTextLength = [UMComKit getStringLengthWithString:realTextString] - topicAndUserLength;
|
||||
return realTextLength;
|
||||
}
|
||||
|
||||
/*
|
||||
// Only override drawRect: if you perform custom drawing.
|
||||
// An empty implementation adversely affects performance during animation.
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
// Drawing code
|
||||
}
|
||||
*/
|
||||
|
||||
-(BOOL)checkMaxLength:(NSString*)text
|
||||
{
|
||||
if (!text) {
|
||||
return NO;
|
||||
}
|
||||
NSInteger curLength = [UMComKit getStringLengthWithString:text];
|
||||
if (curLength> self.maxTextLenght ) {
|
||||
self.noticeLabel.hidden = NO;
|
||||
//显示noticeLabel的位置
|
||||
self.noticeLabel.frame = CGRectMake(self.contentOffset.x,self.contentOffset.y, self.bounds.size.width, self.bounds.size.height);
|
||||
[self performSelector:@selector(hiddenTextView) withObject:nil afterDelay:0.8f];
|
||||
return YES;
|
||||
}
|
||||
else{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UMComHighLightTextUnit
|
||||
|
||||
- (instancetype)initWithTextUnitWithText:(NSString *)text
|
||||
font:(UIFont *)font
|
||||
textColor:(UIColor *)color
|
||||
range:(NSRange)range
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.text = text;
|
||||
self.textColor = color;
|
||||
self.font = font;
|
||||
self.range = range;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (UMComHighLightTextUnit *)textUnitWithText:(NSString *)text
|
||||
font:(UIFont *)font
|
||||
textColor:(UIColor *)color
|
||||
range:(NSRange)range
|
||||
{
|
||||
UMComHighLightTextUnit *textUnit = [[UMComHighLightTextUnit alloc]initWithTextUnitWithText:text font:font textColor:color range:range];
|
||||
return textUnit;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user