首先从github下载 https://github.com/wezm/RegexKitLite
导入.h和.m文件后为RegexKitLite.m添加编译标记-fno-objc-arc。添加动态库libicucore.dylib

UITextView *tv = [[UITextView alloc]init];
    tv.x = 20;
    tv.y = 200;
    [self.view addSubview:tv];

1初始化一个属性字符串

NSString *text = @"https://www.baidu.com 今天发送了[笑cry]一件很有意思的事情[笑尿]。";
//2 指定匹配规则
   // 表情的规则
    NSString *emotionPattern = @"\\[[a-zA-Z\\u4e00-\\u9fa5]+\\]";
    // @的规则
    NSString *atPattern = @"@[0-9a-zA-Z\\u4e00-\\u9fa5-_]+";
    // #话题#的规则
    NSString *topicPattern = @"#[0-9a-zA-Z\\u4e00-\\u9fa5]+#";
    // url链接的规则
    NSString *urlPattern = @"[a-zA-z]+://[^\\s]*";
    //3 对匹配到的范围进行高亮,只需要调用NSMutableAttributedString的addAttribute:::属性对特定范围的文字设置颜色属性。
    NSString *pattern = [NSString stringWithFormat:@"%@|%@|%@|%@",atPattern,emotionPattern,topicPattern,urlPattern];

// 把[表情]替换成attachment图片,不能用replace和insert,因为会改变后面的相对位置,应该先拿到所有位置,最后再统一修改。
    // 应该打散特殊部分和非特殊部分,然后拼接。
    NSMutableArray *parts = [NSMutableArray array];
    
 
    
    [text enumerateStringsMatchedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
        
        if ((*capturedRanges).length == 0) return;
        
        TextSegment *seg = [[TextSegment alloc] init];
        seg.text = *capturedStrings;
        seg.range = *capturedRanges;
        seg.special = YES;
        //判断是否是表情,表情的特点是有[ ]
        seg.emotion = [seg.text hasPrefix:@"["] && [seg.text hasSuffix:@"]"];
        
        [parts addObject:seg];
    }];
    
    [text enumerateStringsSeparatedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
        
        if ((*capturedRanges).length == 0) return;
        
        TextSegment *seg = [[TextSegment alloc] init];
        seg.text = *capturedStrings;
        seg.range = *capturedRanges;
        seg.special = NO;
        [parts addObject:seg];
        
    }];
    
    //通过上面的代码,我们把所有的文字部分都放入了parts数组中,为了拼接方便,我们应该按照位置的起始排序,从前到后依次拼接。
    //这就需要对parts数组依据模型的range.location属性排序,比较常用的是根据block排序。
    //block传入两个数组中的对象obj1、obj2,要求返回排序规则NSOrderedAscending、NSOrderedSame、NSOrderedDescending。
    //NSOrderedAscending指的是obj1<obj2,系统默认按照升序排序,因此为了实现升序,发现obj1<obj2应该返回NSOrderedAscending。
    [parts sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        
        TextSegment *ts1 = obj1;
        TextSegment *ts2 = obj2;
        
        // Descending指的是obj1>obj2
        // Ascending指的是obj1<obj2
        // 要实现升序,按照上面的规则返回。
        
        // 系统默认按照升序排列。
        if (ts1.range.location < ts2.range.location) {
            return NSOrderedAscending;
        }
        
        return NSOrderedDescending;
        
    }];
    
    //接下来只需要从前到后拼接一个新创建的NSAttributedString,根据内容的不同拼接不同的内容。
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] init];
    
    //保存特殊文字
    [self.specialSegments removeAllObjects];
    
    NSInteger cnt = parts.count;
    for (NSInteger i = 0; i < cnt; i++) {
        TextSegment *ts = parts[i];
        if (ts.isEmotion) {
            NSTextAttachment *attach = [[NSTextAttachment alloc] init];
            attach.image = [UIImage imageNamed:@"003"];
            attach.bounds = CGRectMake(0, -3, 15, 15);
            NSAttributedString *emotionStr = [NSAttributedString attributedStringWithAttachment:attach];
            [attributedText appendAttributedString:emotionStr];
        }else if(ts.isSpecial){
            NSAttributedString *special = [[NSAttributedString alloc] initWithString:ts.text attributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];
            // 保存所有特殊文字的内容和位置,保存到模型,再把模型存入数组。
            TextSpecial *spec = [[TextSpecial alloc] init];
            spec.text = ts.text;
            NSInteger loc = attributedText.length;
            NSInteger len = ts.text.length;
            spec.range = NSMakeRange(loc, len);
            [self.specialSegments addObject:spec];
            
            [attributedText appendAttributedString:special];
        }else{
            
            [attributedText appendAttributedString:[[NSAttributedString alloc] initWithString:ts.text attributes:@{NSForegroundColorAttributeName:[UIColor greenColor]}]];
        }
        
    }
    //必须这是这个值,不然高度不够
    [attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14] range:NSMakeRange(0, attributedText.length)];
    
    //然后调用boundingRectWithSize:计算尺寸,注意options必须选择options:NSStringDrawingUsesLineFragmentOrigin才能得到正确尺寸。
    CGSize contentSize = [attributedText boundingRectWithSize:CGSizeMake(320, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;

tv.size = contentSize;
    tv.specialSegments = [self.specialSegments copy];
    tv.attributedText = attributedText;

iOS之图文混排的更多相关文章

  1. ios开发--图文混排(富文本)

    最近准备接一个编辑类的app,所以就查了下相关的功能,并自己试验了下: /** iOS 6之前:CoreText,纯C语言,极其蛋疼 iOS 6开始:NSAttributedString,简单易用 i ...

  2. iOS中 图文混排/自定义图文混排 作者:韩俊强

    指示根视图:(准备几张图片,把label加载在window上) CustomLable *label = [[CustomLable alloc]initWithFrame:CGRectMake(0, ...

  3. iOS支持图文混排的按钮(UIButton)

    创建UIButton子类 直接上代码了 .h文件 创建UIButton子类 直接上代码了 .h文件 #import <UIKit/UIKit.h> @interface GraphicBt ...

  4. iOS SDAutoLayout图文混排-共享

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #526eda } span.s1 { color: #4dbf5 ...

  5. ios图文混排

    图文混排的形式 1. 富文本形式 2. core Text(文字排版) 3. TextKit 4. UIWebView 一.富文本 我们可以采用attributeString来进行图文混排.例如一个文 ...

  6. 【iOS】使用CoreText实现图文混排

    iOS没有现成的支持图文混排的控件,而要用多个基础控件组合拼成图文混排这样复杂的排版,是件很苦逼的事情.对此的解决方案有使用CoreText进行绘制,或者使用TextKit.本文主要讲解对于CoreT ...

  7. 高性能图文混排框架,构架顺滑的iOS应用-b

    About GallopGallop是一个功能强大.性能优秀的图文混排框架. Features主要用于解决以下需求: 滚动列表的性能优化.Gallop使用异步绘制.视图层级合并.观察mainRunlo ...

  8. IOS开发UI篇--一个支持图文混排的ActionSheet

    一.简单介绍 UIActionSheet是IOS提供给我们开发人员的底部弹出菜单控件.一般用于菜单选择.操作确认.删除确认等功能.IOS官方提供的下面方式对UIActionView进行实例化: - ( ...

  9. iOS火焰动画效果、图文混排框架、StackView效果、偏好设置、底部手势等源码

    iOS精选源码 高性能图文混排框架,构架顺滑的iOS应用. 使用OpenGLE覆盖阿尔法通道视频动画播放器视图. 可选最大日期截至当日日期的日期轮选器ChooseDatePicker 简单轻量的图片浏 ...

随机推荐

  1. Voting

    Voting time limit per test 1 second memory limit per test 256 megabytes input standard input output ...

  2. 用 Python 脚本实现对 Linux 服务器的网卡流量监控

    *这篇文章网上已经有相关代码,为了加深印象,我做了相关批注,希望对朋友们有帮助 工作原理:基于/proc文件系统 Linux 系统为管理员提供了非常好的方法,使其可以在系统运行时更改内核,而不需要重新 ...

  3. slf4j 之logback日志之环境安装【一】

    一.maven引用. 传送门:http://www.slf4j.org/manual.html#projectDep <dependency> <groupId>ch.qos. ...

  4. javascript location对象

    location用于获取或设置窗体的URL,并且可以用于解析URL. location.[属性|方法] 1.location对象属性图示: 2.location 对象属性: 3.location 对象 ...

  5. Uploadifive 使用教程【结合七牛】

    Uploadify是一个基于JQuery的多文件上传JS组件,高度定制,两个版本可供选择.flash版本在最新的Safari等不再支持flash的浏览器或者一些手机浏览器中就无法正常的加载使用,因此推 ...

  6. android中RelativeLayout无法填充ScrollView布局的问题

    ScrollView是解决布局过长的情况下使用,一遍其下面会有个顶部布局,我项目里面是RelativeLayout,但是RelativeLayout无论设置 android:layout_height ...

  7. 《JS权威指南学习总结--第六章 对象》

    内容要点: 一.对象定义 对象是JS的基本数据类型.对象是一种复合值:它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值. 对象也可看做是属性的无序集合,每个属性都是一个名/值对. 属性 ...

  8. post请求和get请求

    get请求在链接后面带参数,容易出现乱码,是坑(慎用),有固定的长度 一般的用的就是post方式 <form action="<%=basePath%>upload&quo ...

  9. hdu_4417_Super Mario(主席树)

    题目链接:hdu_4417_Super Mario 题意: 给你n个树,有m个询问,每个询问有一个区间和一个k,问你这个区间内不大于k的数有多少个. 题解: 考虑用主席树的话就比较裸,当然也可以用其他 ...

  10. 关于c++的引用

    引用的本质 引用事实上就是两个变量指向同一个地址 int x; int &y = x; cout << &x << endl; cout << &a ...