UITextView-使用集合

键盘弹出来时,改变工具栏的高度,
想要实现键盘和工具栏一起往上移动的效果,

添加动画,调用[self.view layoutIfNeeded];方法即可
image.png

注意:

    #UITextView的高度,一定要大于输入文字的高度,不然输入文字的时候会晃动,而且还会显示不全哦。所以富文本的时候高度是个大事。
    UITextView *titleView = [[UITextView alloc] initWithFrame:CGRectMake(15, 20, SCREEN_WIDTH-30, 30)];
    titleView.font = [UIFont systemFontOfSize:24];
    #系统Bug。(UITextView文字和占位文字偏移了10的间距)
    titleView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, -10);
    titleView.backgroundColor=[UIColor yellowColor];
    [self.view addSubview:titleView];
1,解决textView输入内容的时候,光标下沉。
//解决textView输入内容的时候,光标下沉。
    self.textField_t.textContainerInset = UIEdgeInsetsMake(5, 0, 0, 0);
2,输入了100行,然后输入第一行内容,那么会自动跑到底部。这句就是为了防止回到底部
    //输入了100行,然后输入第一行内容,那么会自动跑到底部。这句就是为了防止回到底部
    self.textView_c.layoutManager.allowsNonContiguousLayout = NO;
3,自定义view中textview滚动失效 iOS(自定义view放在了一个VC中)
#解决方法:
在VC中
-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    //自定义view中的TextView的scrollEnabled需要在VC加载结束后手动打开一次,不然会把默认YES改为NO。
    self.detailView.textView_detail.scrollEnabled = YES;
}
4,添加图片附件
    //添加图片附件
    NSTextAttachment *attach = [[NSTextAttachment alloc] init];
    attach.image = [UIImage imageNamed:@"1.jpg"];
    attach.bounds = CGRectMake(0, 0, 100, 100);
    //附件是不可变属性字符串
    NSAttributedString *attributedString = [NSAttributedString attributedStringWithAttachment:attach];
    NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:@"点击分手克里斯丁建安费垃圾啊啥都离开房间撒的李开复"];
    [attributedStr insertAttributedString:attributedString atIndex:attributedStr.length];

    self.textView.attributedText = attributedStr;
5,获取光标位置
#注意:使用时候判断是否为空:
    NSRange rg = self.textView.selectedRange;
     if (rg.location != NSNotFound)
    {
        NSLog(@"光标位置:%d",rg.location);
    }

6,iOS中TextView显示HTML文本

7,输入时上下晃动

CGRect line = [textView caretRectForPosition:textView.selectedTextRange.start];
    CGFloat overflow = line.origin.y + line.size.height    - ( textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top );
    if ( overflow > 0 ) {
        // We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
        // Scroll caret to visible area
        CGPoint offset = textView.contentOffset;
        offset.y += overflow + 7;
        // leave 7 pixels margin
        // Cannot animate with setContentOffset:animated: or caret will not appear
        [UIView animateWithDuration:.2 animations:^{
            [textView setContentOffset:offset];
        }];
    }
8,UITextView加载HTML数据(左间距没有调试成功,暂用wkwebView.)

- (void)viewDidLoad {
    [super viewDidLoad];

    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, [UIScreen mainScreen].bounds.size.width - 20, [UIScreen mainScreen].bounds.size.height - 20)];
    textView.delegate = self;
    textView.editable = NO; // 非编辑状态下才可以点击Url]
//    textView.fontFloat = 18.;
    NSString *textStr=@"<p>现在互联网,断章取义的东西大家最喜欢玩了,本来是个很严肃很励志的一句话,但是把头尾一截,就变得很有趣味了</p><p><br/></p><p>先订一个能达到的小目标(严肃认真脸.jpg)</p><p>比方说我先挣它一个亿(严肃轻松脸.png)</p><p><img src=\"http://img.woshipm.com/TTW_QUESTION_201608_20160829170712_0539.jpg\" title=\"\" width=\"385\" height=\"415\" style=\"width: 385px; height: 415px;\"/></p><p>首尾的强大反差给人一种无奈到好笑的感觉,跟比尔盖茨很有名的那张3秒赚辆兰博基尼有异曲同工之妙。</p><p><br/></p><p>说的随便点吧,就是大家觉得这东西好玩搞笑,极具讽刺性,跟大家的生活现状形成强烈的对比,明明就是苦逼屌丝一辈子赚不到一千万的角儿,却要看着人家定个小目标随便弄他一个亿,我的妈呀,人与人之间的差别距离好几个爹呀。</p><p>互联网现在信息传递快,大家爱自嘲、爱起哄,像这种能够开名人玩笑,为生活补充点乐子的事,而且还能表达一下自己对生活的挖苦、讽刺,所以转了也就转了<br/></p>";
//    NSString *linkStr = [textView.text substringWithRange:range];
    
    NSMutableAttributedString *attributedString = [self changeHtmlStringToAttributeString:textStr];
//    [attributedString addAttribute:NSLinkAttributeName value:@"http://img.taopic.com/uploads/allimg/111231/6755-11123114022199.jpg" range:NSMakeRange(0, 6)];

    textView.attributedText = attributedString;
    [self.view addSubview:textView];

#测试
(

 self.jq_textView.delegate = self;
    self.jq_textView.editable = NO; // 非编辑状态下才可以点击Url]
    //    textView.fontFloat = 18.;
    NSString *textStr=@"<div style=\"margin:75px;\"><h2 style=\"font-size: 13px;color: #888;\">会员权益简介 -----------------</h2><div style=\"padding-left:70px;\"><h2 style=\"font-size: 13px;color: #888;\">会员专享价</h2><h3 style=\"font-size: 13px;color: #999;margin: 30px 35 0 0;\">权益说明</h3><p style=\"font-size: 13px;color: #999;margin: 0 35 15px 0;\">商品促销信息以商品详情页“促销”栏中的信息为准;商品的具体售价以订单结算页价格为准;如您发现活动商品售价或促销信息有异</p><h3 style=\"font-size: 13px;color: #999;margin:10px 35 0 0;\">权益等级</h3><p style=\"font-size: 13px;color: #999;margin: 0 35 15px 0;\">信息以商品详情页“促销”栏</p><h3 style=\"font-size: 13px;color: #999;margin: 10px 35 0 0;\">其他说明</h3><p style=\"font-size: 13px;color: #999;margin: 0 35 15px 0;\">商品促销信息以商品详情页“促销”栏中的信息为准;商品的具体售价以订单结算页价格为准;如您发现活动商品售价或促销信息有异</p></div></div>";
    //    NSString *linkStr = [textView.text substringWithRange:range];
    
    NSMutableAttributedString *attributedString = [self changeHtmlStringToAttributeString:textStr];
    
    self.jq_textView.attributedText = attributedString;


  )



}

-(NSMutableAttributedString *)changeHtmlStringToAttributeString:(NSString *)htmlString{
    NSString *newString = htmlString;
    
    
    //图片自适应宽高,只限制图片的最大显示宽度,这样就能做到自适应
    newString =[NSString stringWithFormat:@"<html>"
                "<head>"
                
                "</style>"
                "<style>*{margin:3px 0px 3px 0px;padding:0 ;max-width:%f;}</style>"
                "</head>"
                "<body>%@</body>"
                "</html>",self.view.frame.size.width-30,newString];
    NSData *data = [newString dataUsingEncoding:NSUnicodeStringEncoding];
    
    NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
    NSMutableAttributedString *htmlAttribute = [[NSMutableAttributedString alloc] initWithData:data
                                                                                       options:options
                                                                            documentAttributes:nil
                                                                                         error:nil];
    
    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    
    //设置文字的行间距
    [paragraphStyle setLineSpacing:5];
    
    [htmlAttribute addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [htmlAttribute length])];
    //设置文字的颜色
    [htmlAttribute addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, htmlAttribute.length)];
    
    //设置文字的大小
    [htmlAttribute addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14] range:NSMakeRange(0, htmlAttribute.length)];
    
    return htmlAttribute;
    


#测试
(
      NSString *newString = htmlString;
    
    NSData *data = [newString dataUsingEncoding:NSUnicodeStringEncoding];
    
    NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
    NSMutableAttributedString *htmlAttribute = [[NSMutableAttributedString alloc] initWithData:data
                                                                                       options:options
                                                                            documentAttributes:nil
                                                                                         error:nil];
    
    return htmlAttribute;
)
}
9,自定义 UITextView 关键字高亮与点击检测
10,替换属性字符串中的图片为字符
#:属性字符串attributeString
    //方法一
//    NSMutableString *plainString = [NSMutableString stringWithString:attributeString.string];
//    __block NSUInteger base = 0;
//    [self enumerateAttribute:NSAttachmentAttributeName inRange:NSMakeRange(0, self.length)
//                     options:0
//                  usingBlock:^(LiuqsTextAttachment *value, NSRange range, BOOL *stop) {
//                      if (value) {
//                          [plainString replaceCharactersInRange:NSMakeRange(range.location + base, range.length)
//                                                     withString:value.emojiTag];
//                          base += value.emojiTag.length - 1;
//                      }
//                  }];
    
    //方法二(推荐)
    NSMutableAttributedString *mutableAttributeString = [[NSMutableAttributedString alloc] initWithAttributedString:attributeString];
    [mutableAttributeString enumerateAttribute:@"NSAttachment" inRange:NSMakeRange(0, self.length) options:0 usingBlock:^(id  _Nullable value, NSRange range, BOOL * _Nonnull stop) {
        
        NSLog(@"value===%@",value);
        NSLog(@"range===%@",NSStringFromRange(range));

        if ([value isKindOfClass:[NSTextAttachment class]]) {
            LiuqsTextAttachment *attachment = (LiuqsTextAttachment *)value;
            [mutableAttributeString replaceCharactersInRange:range withString:attachment.emojiTag];
        }
        
    }];
    
    return [mutableAttributeString string];
11,清空UItextView的所有内容
self.toolView.jq_inputView.text = @" ";
[self.toolView.jq_inputView deleteBackward]; //删除一个字节
12,UITextView/UITextField检测并过滤Emoji表情符号
当用户切换键盘为Emoji表情时,输入的表情不响应(即表情符号不显示到UITextView或UITextField)。这里可以通过UITextView或UITextField的回调和是否为emoji键盘:

 /*
 *第一种方法,简单粗暴
 */
 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
 {
     // 不让输入表情
     if ([textView isFirstResponder]) {
         if ([[[textView textInputMode] primaryLanguage] isEqualToString:@"emoji"] || ![[textView textInputMode] primaryLanguage]) {
             NSLog(@"输入的是表情,返回NO");
             UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"警告!" message:@"不能输入表情" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定",nil];
             [alertView show];
             return NO;
         }
     }
     return YES;
 }

为避免当用户通过中文键盘输入中文“哈哈”后出现可选文字中选中的Emoji笑脸,最后在- (void)textFieldDidEndEditing:(UITextField *)textField方法中统一通过检查最终字符串textField/textView.text的内容,通过Emoji筛unicode编码来判断是否存在Emoji表情,如果存在则提醒用户做修改。

 //在输入完成时,调用下面那个方法来判断输入的字符串是否含有表情
 - (void)textFieldDidEndEditing:(UITextField *)textField
 {
     if ([self stringContainsEmoji:textField.text]) {
         NSLog(@"含有表情");
         UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"警告!" message:@"输入内容含有表情,请重新输入" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定",nil];
         [alertView show];
         textField.text = @"";
         [textField becomeFirstResponder];
     }else {
         NSLog(@"不含有表情");
     }

 }

 /*
  *第二种方法,利用Emoji表情最终会被编码成Unicode,因此,
  *只要知道Emoji表情的Unicode编码的范围,
  *就可以判断用户是否输入了Emoji表情。
  */
 - (BOOL)stringContainsEmoji:(NSString *)string
 {
     // 过滤所有表情。returnValue为NO表示不含有表情,YES表示含有表情
     __block BOOL returnValue = NO;
     [string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {

         const unichar hs = [substring characterAtIndex:0];
         // surrogate pair
         if (0xd800 <= hs && hs <= 0xdbff) {
             if (substring.length > 1) {
                 const unichar ls = [substring characterAtIndex:1];
                 const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                 if (0x1d000 <= uc && uc <= 0x1f77f) {
                     returnValue = YES;
                 }
             }
         } else if (substring.length > 1) {
             const unichar ls = [substring characterAtIndex:1];
             if (ls == 0x20e3) {
                 returnValue = YES;
             }
         } else {
             // non surrogate
             if (0x2100 <= hs && hs <= 0x27ff) {
                 returnValue = YES;
             } else if (0x2B05 <= hs && hs <= 0x2b07) {
                 returnValue = YES;
             } else if (0x2934 <= hs && hs <= 0x2935) {
                 returnValue = YES;
             } else if (0x3297 <= hs && hs <= 0x3299) {
                 returnValue = YES;
             } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
                //想过滤的字符可以在这里做处理
                if (![substring isEqualToString:@"®"]) {
                    returnValue = YES;
                }
             }
         }
     }];
     return returnValue;
 }

13,UITextView插入图片时,通常会想在前后插入换行(\n),但是呢,如果加了行高之类的东西,那么就尴尬了,因为计算的高度会出问题。
#方案一:在图片前后分别再插入一个附件,高度为0或1,宽度为屏幕宽。
#first,尴尬了,附件有个默认的高度,大概10-15左右吧,
这个高度是去不掉的,而且就算高度为0,还是可以点击到附件。
如果想做点击图片放大的话,这又是个难题。
#final,放弃方案一。
#方案二:回归添加换行(\n)
        /*
            1,取图片前一位,如果是图片,那么就不添加回车,如果不是图片,那么就添加回车。
            2,取前一位时注意图片是第一位的情况。
            3,经测试得到,一个回车是20的高度。如果有一个回车就在totalImageHeight的基础上添加20。
            4,注意属性字符要准备2份,一份用来展示(带回车),一份把图片替换为空(不带回车),因为totalImageHeight已经把回车的高度加上了。计算纯文本就可以了。
            5,替换文本后需要重新设置富文本属性,不然会恢复初始化状态,行高间距字体大小都没了。
            6,连续两张图片的算一个间距,所以这里要减去有多少个连续的图片,最后测试选择一个连续的两张图-10的间距。
            7,换行的模式选择NSLineBreakByCharWrapping,因为这样可以兼容到字母、数字。
               举例:paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
            8, 根据URL找到指定缓存(如果存在的话)
               UIImage* image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:url];
            9,插入图片原理:看SDWebImage中是否有缓存图片,有则把正则匹配的图片范围直接替换为图片,否则,先默认插入一个宽高均为SCREEN_WIDTH-25的附件,然后SDWebImage异步下载图,下载成功之后,判断找到对应的附件,替换,textView高度减去差值,重新添加到tableview的头部。
         
         */

14,系统UITextView可以开始识别手机号、网址等。
textView.delegate = self;
textView.dataDetectorTypes = UIDataDetectorTypeLink; //开启识别链接

UIDataDetectorTypePhoneNumber  :识别手机号
UIDataDetectorTypeLink  :识别链接
UIDataDetectorTypeAll  :识别所有


#点击链接会走这个方法
//链接委托(链接最好用一个括号括起来,或者在链接后面加个空格。)
- (BOOL)textView:(UITextView*)textView
    shouldInteractWithURL:(NSURL*)URL
                  inRange:(NSRange)characterRange
{
    NSLog(@"URL tap handle:%@", URL);

    return YES; //返回yes,点击链接的时候就会自动打开。
}

#点击附件会走这里的方法
/*
 附件委托新方法。
 返回YES,可以从下面弹出复制图片或保存图片,但是呢,不是很好看。
 */
- (BOOL)textView:(UITextView*)textView
    shouldInteractWithTextAttachment:(NSTextAttachment*)textAttachment
                             inRange:(NSRange)characterRange
                         interaction:(UITextItemInteraction)interaction
{
    //获取附件
    CustomTextAttachMent* attachment = (CustomTextAttachMent*)textAttachment;

    NSLog(@"%@", attachment.imgURL); //获取原图URL

#这里我使用HJPhotoBrowser做了点击图片放大的功能。
    self.clickImgURL = attachment.imgURL;
    self.clickImg = attachment.image;

    HJPhotoBrowser* photoBrowser = [HJPhotoBrowser new];
    photoBrowser.delegate = self;
    //    photoBrowser.currentImageIndex = indexPath.item;
    photoBrowser.imageCount = 1;
    photoBrowser.sourceImagesContainerView = self.view;

    [photoBrowser show];

    return NO;
}

15,UITextView实现左右点击效果

感觉两个手势就搞定了,待定(该博客还没看)

16,UITextView实现富文本
        /*
         1,取图片前一位,如果是图片,那么就不添加回车,如果不是图片,那么就添加回车。
         2,取前一位时注意图片是第一位的情况。
         3,经测试得到,一个回车是20的高度。如果有一个回车就在totalImageHeight的基础上添加20。
         4,注意属性字符要准备2份,一份用来展示(带回车),一份把图片替换为空(不带回车),因为totalImageHeight已经把回车的高度加上了。计算纯文本就可以了。
         5,替换文本后需要重新设置富文本属性,不然会恢复初始化状态,行高间距字体大小都没了。
         6,连续两张图片的算一个间距,所以这里要减去有多少个连续的图片,最后测试选择一个连续的两张图-10的间距。
         7,换行的模式选择NSLineBreakByCharWrapping,因为这样可以兼容到字母、数字。
         举例:paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
         8, 根据URL找到指定缓存(如果存在的话)
         UIImage* image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:url];
         9,插入图片原理:看SDWebImage中是否有缓存图片,有则把正则匹配的图片范围直接替换为图片,否则,先默认插入一个宽高均为SCREEN_WIDTH-25的附件,然后SDWebImage异步下载图,下载成功之后,判断找到对应的附件,替换,textView高度减去差值,重新添加到tableview的头部。
         
         10,注意替换SDWebImage下载完成的图片时,要重新创建一个CustomTextAttachMent,不然一张图的时候,第一次进入显示失败。
         */
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容