富文本的一种全新的编程方式 —— NudeIn

富文本

iOS系统优雅的UI交互界面是我们使用iPhone的理由之一,这当然少不了其中优美的多信息文本了。多信息文本也被称为富文本,在Cocoa里也被称为AttributedText。

富文本特别的地方,在于其表现了纯文本所无法表现出来的信息,这些信息可以代表文本所表达出来的感情,比起单纯的通过文字内容来表达感情,这种感情很显然具有强烈的冲击力。

“喜悦”一词,可以像纯文本这般干巴巴,也可以像下图艺术字那般喜气洋洋,这一切都是富文本所能表达出来的强烈感情。

image

当然了,上面的“喜悦”,更多是偏向艺术方面的表达,我们所要说的富文本,虽然也包含了这方面,却不止于此。

编程界的富文本,不仅仅能够表达感情,还能表达出常规艺术字所无法表达出来的信息,比如:

超链接:让你的文本能够产生交互

段落编排:定义文字的格局,让格局符合你所需要的结构,以方便读者的阅读

身份:粗体作为标题,灰色字体作为提示,常规体作为正文等,在许多开发案例之中,我们往往需要用到这种身份标志

······

富文本的编程方式

作为iOS程序员,我们在代码里该怎么创造富文本呢?一种方式是通过苹果公司的官方API来编写富文本代码,另一种方式则是通过第三方库,笔者想其中最具代表性的应该是YYText了。

通过官方API

通过官方的API,大家马上想到的便是NSAttributedString了。它是基于TextKit的一种相对简单的富文本API,相比定制能力更高的TextKit,其用法要简单不少,且满足绝大部分开发需求。
假如我们需要实现这样一个富文本:


其中 BlueLink 和 RedLink 为链接

通过NSAttributedString大体可以这么做:

        UITextView *textView= [UITextView new];
        NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"this is a BlueLink,and this is a RedLink"];
        [string addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14] range:NSMakeRange(0, 10)];
        [string addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, 10)];
        [string addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17] range:NSMakeRange(10, 8)];
        [string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(10, 8)];
        [string addAttribute:NSLinkAttributeName value:@"https://www.jianshu.com" range:NSMakeRange(10, 8)];
        [string addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14] range:NSMakeRange(18, 13)];
        [string addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(18, 13)];
        [string addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17] range:NSMakeRange(33, 7)];
        [string addAttribute:NSLinkAttributeName value:@"https://www.jianshu.com" range:NSMakeRange(33, 7)];
        [string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(33, 7)];
        textView.linkTextAttributes = @{};
        textView.attributedText = string;

如此之多的代码量,只是因为一段小小的样式,写起来竟如此麻烦,不仅无法轻易从代码读出其意图,还冗长无比,更甚者,如果你想自己处理链接的回调,还得自己实现UITextView的相关委托。
事实上,相比更底层的API如TextKit、CoreText,NSAttributedString已经相当之简单了,若要是在更早之前,iOS开发者们只能面对CoreText这种相当底层的API,那个时候的富文本实现难度非常之高。尽管如此,NSAttributedString用起来还是不太尽如人意。

通过YYText

那么使用YYText会怎么实现?看过其源代码都能知道,该作者相当厉害。但是通过其Github文档了解到,其编程方式有所改善,代码量减少了,易读性稍微加强了一些,但是在编程方式上却未有太大改变,写起来的感觉其实还是如同上面那样别扭。具体请了解 https://github.com/ibireme/YYText

通过一种新的方式 NudeIn
如果你用过Masonry,你一定会被其独特的编程方式所吸引。Masonry在手写约束代码上完全让我们摆脱了原生约束代码令人抓狂的编程方式,Masonry是按照人的思维进行设计的。换句话说,你脑海里第一时间所想的,就是Masonry如何进行的。

笔者自身也是Masonry的忠实用户,收到其灵感的激发,笔者重新设计了一下富文本的编程方式 NudeIn。先不说别的,让我们来看看上面那个例子使用这种新的方式应该如何实现。


其中 BlueLink 和 RedLink 为链接

使用 NudeIn,我们可以这么做:

NudeIn *nude = [NudeIn make:^(NUDTextMaker *make) {
    make.text(@"this is a ").font(14).color([UIColor blackColor]).attach();
    make.text(@"BlueLink").font(17).color([UIColor blueColor]).link(self,@selector(linkHandler:)).attach();
    make.text(@", and this is a ").font(14).color([UIColor blackColor]).attach();
    make.text(@"RedLink").font(17).color([UIColor redColor]).link(self,@selector(linkHandler:)).attach();
}];

实现回调 linkHandler

- (void)linkHandler:(NUDAction *)action {
    if ([action isKindOfClass:[NUDLinkAction class]]) {
        NUDLinkAction *linkAction = (NUDLinkAction *)action;
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:linkAction.string message:nil preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        }]];
        [self presentViewController:alertController animated:YES completion:nil];
    }
}

代替冗长难以阅读的原生代码,笔者将不同属性的文字拆分成了一个个组件,每个组件通过类似Masonry的方式来定义自己本身的属性。NudeIn 让你可以轻松将一个复杂的富文本标签按照顺序拆分成各种不同的控件,每个控件可以集成任何预设的属性。

当然,冗余还是有的,如某些案例里,有大量不同属性的文字也会拥有许多相似点,如仅仅是颜色不一样的话,按照上面的编程方式,将会有许多冗余代码。

为了减少这种冗余,笔者引入了 Template,通过Template,你可以将消除这种冗余:

NudeIn *nude = [NudeIn make:^(NUDTextMaker *make) {
    make.textTemplate(@"normal").font(14).color([UIColor blackColor]).attach();
    make.textTemplate(@"highlight").font(17).color([UIColor blueColor]).attach();
    make.text(@"this is a ").nud_attachWith(@"normal");
    make.text(@"BlueLink").nud_attachWith(@"highlight");
    make.text(@", and this is a ").nud_attachWith(@"normal");
    make.text(@"RedLink").color([UIColor redColor]).nud_attachWith(@"highlight");
}];

上面的例子,笔者定义了两个模板,一个 normal 模板代表常规字体,一个 highlight 模板代表高亮字体,且颜色默认为蓝色。特别的,对于 “RedLink” 这个组件,相比BlueLink有一些差异,无需担心,模板里的任何属性都是可以覆盖。笔者就通过重新定义它的颜色属性来覆盖原有模板上的颜色属性。
通过这种方式,对于复杂度不高的富文本来说并没有什么必要,但是对于高复杂度文本来说,它大大减少了冗余代码,效果会非常好,在易读性和易写性上也没减弱的地方。

不仅仅是template,你还可以为所有组件定义通用的属性:

NudeIn *nude = [NudeIn make:^(NUDTextMaker *make) {
    make.allText().font(14).color([UIColor redColor]).attach();
    make.text(@"").attach();
    .....
}];

这样,所有的组件都将是字号14,颜色为红色的组件。

除了常规文本的标签,NudeIn 还可以非常方便的为文字添加任何图片,如表情符号这种。

NudeIn *nude = [NudeIn make:^(NUDTextMaker *make) {
    make.image(@"image").origin(0,0).size(0,0).vertical(1).attach();
    make.text(@"text").attach();
    .....
}];

这样,image 图标就会挂在text文字前面。
如果你想,你还可以通过 origin 和 size 来定义它的rect,通过 vertical 来调整它的垂直升降。
特别的,image 默认使用 [UIImage imageName:]来获取图片,如果你想使用自己生成的图片,可以通过 imageRes 标签,传入UIImage 对象。
你甚至还可以通过 imageTemplate 定义 image 的模板,其用法就像文字组件一样,没有任何区别。

在笔者的工作里,笔者也引入了这款富文本库进行使用,在使用的过程中笔者发现自己越来越依赖这款控件了,有时候就算不是富文本,也感觉使用 NudeIn 会比使用传统的 UILabel 要来得舒服,不知道是不是有点问题呢,

NudeIn 目前还在完善之中,文档相对也不是太完善,但是笔者认为它非常棒,当前已经引入 highlight 功能,并打算加入 press 和 longPress 属性来代替无法自定义高亮的 link 属性

NudeIn 地址:https://github.com/hon-key/Nudeln

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_X自主阅读 15,977评论 3 119
  • 小女孩问,妈妈,这是什么植物呀? 妈妈说,这应该是叫什么刺,记不起来了。 小女孩说,它好像芭蕉扇呀! 眼睛一亮一亮...
    挨姑姑洞穴小面团阅读 475评论 0 2
  • 文中所描述的遵循协议的类型,之所以写为类型是因为在Swift中遵循协议的可以是类,结构体或者协议等等,官方文档用t...
    Justin_S_Wang阅读 1,618评论 0 5
  • 多少时候,因为得不到,假装不想要。 心脏是一座有两间卧室的房子,一间住着痛苦,一间住着欢乐,人不能笑得太响,否则笑...
    白色橡皮擦阅读 249评论 0 0
  • 零 火光在眼里四处尖叫着。 “别出声。跟我走。” 一 先知是没有感情的。 大概是这样吧,我想。这就是这个世界还能存...
    陈千放阅读 376评论 0 0