我们知道微博可以在编辑中添加话题,比如将两个"#"号之间的字体变为蓝色等,最近项目当中需要用到这样的功能,就考虑了一下如何实现这个功能~

首先说一下我们的要求:

  • 两个"#"号之间的字体变为蓝色
  • 两个"#"为一对,第二对"#"号则是从第3个"#"到第四个"#"之间的字符
  • "#"号中的字符为空或则多过20个为无效话题,不变蓝色

思路:

  1. 要想要显示不一样颜色的字体在UITextView中,我们不用CoreText也不用UITextKit,就用最简单的NSMutableAttributedString,使用NSMutableAttributedString可以将特殊范围内的字符标记为不同的样式.
  2. 使用正则来搜索符合标准的字符串所处的位置,用来改变此段字符的格式
  3. 监听UITextView的字符改变,每改变一次就将所有的字符重新匹配一遍,绘制富文本,并赋值给UITextView

使用NSMutableAttributedString标记特殊字符

- (void)viewDidLoad {[super viewDidLoad];// 创建一个textViewUITextView *textView = [[UITextView alloc]init];textView.textAlignment = NSTextAlignmentCenter;textView.backgroundColor = [UIColor lightGrayColor];textView.frame = CGRectMake(0, 0, 300, 300);textView.center = self.view.center;textView.font = [UIFont systemFontOfSize:30];// 创建一个NSMutableAttributedStringNSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc]initWithString:@"给#时间#一点时间!"];//设置区间(1,4)的字体为蓝色[attributedStr addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(1, 4)];// 所有的字体大小为25号[attributedStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:25] range:NSMakeRange(0, 10)];// 将attributedText赋值给textViewtextView.attributedText = attributedStr;[self.view addSubview:textView];
}
复制代码

通过正则来搜索符合标准的字符串

// 传入一个字符串,返回排版好的attributedString
+ (NSMutableAttributedString *)attriStrUseTagModelWithStr:(NSString *)dataStr
{// 创建一个attriStrNSMutableAttributedString *attriStr = [[NSMutableAttributedString alloc]initWithString:dataStr];BOOL endSearch = NO;    // 循环收索符合标准的字符串do {// 通过正则来搜索字符串NSRange range = [dataStr rangeOfString:@"#[^#]{1,20}?#" options:NSRegularExpressionSearch range:NSMakeRange(0, dataStr.length)];// 如果收索完就退出循环if (range.location == NSNotFound) {endSearch = YES;}else{            // 将符合标准的区间标记为蓝色[attriStr addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:range];NSMutableString *replaceStr = [NSMutableString string];// 因为我们用的是sear收索,所以只能匹配到第一符合正则的字符串,我们需要用等长度的字符串替换调,用来收索下一个符合的字符串for (int i = 0; i < range.length; i++) {[replaceStr appendString:@"@"];}dataStr = [dataStr stringByReplacingCharactersInRange:range withString:replaceStr];}} while (!endSearch);    return attriStr;
}
复制代码

结合我们以上内容我们自定义一个UITextView,当你输入的时候就实时替换富文本

#import "BZFilterTextView.h"
#import "BZTagSearTool.h"@interface BZFilterTextView ()
@end@implementation BZFilterTextView- (instancetype)initWithFrame:(CGRect)frame
{self = [super initWithFrame:frame];if (self) {[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textdidChange:) name:UITextViewTextDidChangeNotification object:self];}return self;
}- (void)textdidChange:(NSNotification *)noti
{// 记录当前的光标位置NSRange selRange = self.selectedRange;// 替换富文本self.attributedText = [BZTagSearTool attriStrUseTagModelWithStr:self.text];// 重置原来的光标位置self.selectedRange = selRange;
}- (void)dealloc
{[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
复制代码

结合以上的内容我们来自定义一个textView,可以在输入的时候实时替换textView

注意的问题:

  • 因为正则收索用的是sear所以要将已经收到的内容用其他的非#符号代替
  • 在设置textView的attrituteText时,一定要将之前插入的光标位置先记录下来,在赋值后再赋值上去,以防止用户插入字符后,出现光标到末尾的现象

#####接下来要说一个严重的bug,这是我在输入中文字符中发现的,大概是这个样子的:

这也是实现这个东西困扰我最大的问题,我当时无论如何都想不通,为什么会记录上一次输入的字符并和这次输入的加一块返回回来,还在中间加了一个空格,说下当时我想过的几个思路:

  • 首先,我想到的是因为通过键盘输入的是记录在text中的,而我重新赋值是通过attributeText赋值的,这两个属性都能够改变textView所显示的内容,可能是因为赋值的冲突导致的,那我把text在赋值前给清空,结果发现,清空后还是会记录原来的值
  • 为了测试到底能不能清空,我干脆把attributeText也给清空了,最后发现还是会记录原来的值,那这种方法不行,那为什么无法删除储存的值呢
  • 不知道大家注意到没有,我们使用英文输入法的时候并没有这个问题,难道是因为输入法的问题,可是输入法怎么会影响text的值的储存呢,或许是应为汉字的字符长度和字母不同,导致我计算的range有误,但是打印证明我的计算没有出现错误...(::>_<::)
  • 后来的后来,我甚至想到了每次输入就重新创建一个textView,发现我是用汉字输入法在未确认联想提供的汉字或者回车使用字母是取出的值是空,这也提醒了我,我之所以取不到值,是因为,虽然字母已经显示在了textVeiw上,但是它处于一种联想输入汉字的高亮状态,而不是真实的输入值
  • 我前面把值设置为空,是把真实的值设置为空,但是联想输入的字符在一个我不知道的地方储存着,解决的办法就是,监听当前是否处于联想输入的状态,这个时候不对字符串做处理,当真的显示在textView上的值时,在做处理,实现的方式很简单,在textView的值改变方法里监听状态:
- (void)textdidChange:(NSNotification *)noti
{UITextRange *selectedRange = [self markedTextRange];// 获取高亮字符的位置UITextPosition *position = [self positionFromPosition:selectedRange.start offset:0];//如果没有高亮字符,才计算富文本,否则相当于没有输入 if (!position) {NSRange selRange = self.selectedRange;NSMutableAttributedString *str = [BZTagStringTool attriStrUseTagModelWithStr:self.text];self.attributedText = str;self.selectedRange = selRange;}
}
复制代码
当处于联想输入的时候,虽然监听到textView发生值改变,但是其实并未将其作为textView的内容储存起来~~切记!!!

下面是字符搜索的swift版本,可以在oc中使用:

class BZTagStringTool: NSObject {class func attriStrUseTagModelWithStr(str:String) -> NSMutableAttributedString {let attriStr = NSMutableAttributedString(string: str)var dataStr = strvar endSearch = falsewhile !endSearch {let range = (dataStr as NSString).rangeOfString("#[^#]{1,20}?#", options: .RegularExpressionSearch)if range.location != NSNotFound {attriStr.addAttribute(NSForegroundColorAttributeName, value: UIColorFromRGB(0x5298e6), range: range)let replaceStr = NSMutableString()for _ in 0..<range.length {replaceStr.appendString("@")}dataStr = (dataStr as NSString).stringByReplacingCharactersInRange(range, withString: replaceStr as String)}else{endSearch = true}}attriStr.addAttributes([NSFontAttributeName:UIFont.systemFontOfSize(14)], range: NSMakeRange(0, str.characters.count))return attriStr}
}
复制代码

####踩坑求赞~

特殊标记字段(#)实时富文本显示相关推荐

  1. uni-app富文本图片太大溢出以及富文本显示问题

    原文:https://blog.csdn.net/chenny_/article/details/115534622 优化之前,图片太大 解决方法: 1.在common 目录下新建 index.js: ...

  2. android richtext显示html,RichText Android 平台下的富文本显示控件 @codeKK Android开源站...

    注意:此项目已不再维护 Android 平台下的富文本解析器 流式操作 低侵入性 依赖少,只依赖了disklrucache和support v4 支持 Html 和 Markdown 格式文本 支持图 ...

  3. 富文本图片太大溢出以及富文本显示问题

    优化之前,图片太大 解决方法: 1.在common 目录下新建 index.js: /* graceUI rich-text 加强工具 link : graceui.hcoder.net author ...

  4. Android开发之WebView加载HTML源码包含转义字符实现富文本显示的方法

    老套路先看效果图: WebView加载带有转移字符的HTML源码 再看转义后的字符的效果图: 先看WebView加载HTML源码的方法如下: webview.loadDataWithBaseURL(n ...

  5. swift 展示html富文本,Swift HTML富文本显示

    iOS平台下更灵活 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading ...

  6. layui循环遍历数据_Layui之动态循环遍历出的富文本编辑器显示

    这篇记得是工作中的例子 描述: 平常的富文本显示都是根据静态的html获取id来显示,比如: 富文本内容 layui.use([ "form", "layer" ...

  7. PMEdit一个富文本框可以编辑文本、图片并可以显示GIF动画

    一.在开始之前首先吐槽一下,本人是一个独立开发者,在中国独立开发者就代表一个比较苦逼的行业,特别是对底层东西进行开发者,尤其本人研究方向是编译器.解析器基本上没有公司要,所以出来做个独立开发者.作为独 ...

  8. PMEdit一个富文本框可以编辑文本、并可以显示GIF动画

    PMEdit一个富文本框可以编辑文本.并可以显示GIF动画 发布时间:2013-04-14 发布来源: 护士必必要有同情心和一双愿意工作的手. 一.在开端之前起首吐槽一下,本人是一个自力开辟者,在中国 ...

  9. 富文本粘贴word文档内容图片处理

    最近公司做项目需要实现一个功能,在网页富文本编辑器中实现粘贴Word图文的功能. 我们在网站中使用的Web编辑器比较多,都是根据用户需求来选择的.目前还没有固定哪一个编辑器 有时候用的是UEditor ...

最新文章

  1. 同时上哈佛,还一起一作发Nature!这对95后学霸情侣让人慕了……
  2. Oracle学习笔记整理手册
  3. ImageView scaleType
  4. python图片横向合并_python实现图片横向和纵向拼接
  5. python获取指定端口流量_利用python获取nginx服务的ip以及流量统计信息
  6. CSS3的边框(三)
  7. LINQ to SQL语句(1)之Where
  8. 重磅开源!《30天吃掉那只 TensorFlow2.0 》(附下载)
  9. 解决Fast api打印两次日志的问题
  10. java 银行管理系统怎么储存账户信息_银行管理系统 实现用户注册 登录 存、取款 交易记录查询和修改用户信息等功能...
  11. English trip V2-B 5 Apartment Living 公寓生活 Teacher:Tom
  12. MapReduce过程详解
  13. php 执行bat文件,bat执行PHP文件
  14. (1)ROS安装时Rosdep 报错解决教程
  15. Nodejs搭建前后端分离开发模式下的微信网页项目
  16. 线程死锁、锁死、饥饿、活锁讲解
  17. 内部泄露版!互联网大厂的薪资和职级一览
  18. 轻量级过程改进之综述
  19. 使用Java实现建造者模式
  20. 宽带不能上传发文件_此时此刻(2019年),移动宽带如何了?

热门文章

  1. SAP RETAIL 如何查看分配表是参考哪个PO来创建的?
  2. SAP RETAIL 基于分配表创建采购订单的时候按工厂拆分?
  3. 欧盟为无人机立法,对国产厂商是福还是祸?
  4. 10万视频,所有图像均获授权,Facebook创建大规模Deepfake数据集
  5. 「SAP技术」SAP 如何看序列号被包在哪些HU里?
  6. 「SAP技术」A项目关联公司间退货STO流程
  7. 无人驾驶的落地,是一场AI与人的博弈
  8. 愚蠢的CNN,换个马甲就认不出猫!但,这病能治 | ICLR Oral
  9. 计算机视觉的基本概念
  10. 科普丨深度神经网络与生命的意义