简介

  iOS7 的发布给开发者的案头带来了很多新工具。其中一个就是 TextKit(文本工具箱)。TextKit 由许多新的 UIKit 类组成,顾名思义,这些类就是用来处理文本的。

  1.NSTextStorage    专门用于存储内容的

  2.NSLayoutManager     专门用于管理布局

  3.NSTextContainer   专门用于指定绘制的区域

 字符串(String):要绘制文本,那么必然在某个地方有个字符串存储它。在默认的结构中,NSTextStorage 保存并管理这个字符串,在这种情况中,它可以远离绘制。但并不一定非得这样。使用 TextKit 时,文本可以来自任何适合的来源。例如,对于一个代码编辑器,字符串可以是一棵包含所有显示的代码的结构信息的注释语法树(annotated syntax tree, AST)。使用一个定制的文本存储,这个文本只在后面动态地添加字体或颜色高亮等文本属性装饰。这是第一次,开发者可以直接为文本组件使用自己的模型。只需要一个特别设计的文本存储。即:

  NSTextStorage:如果你把文本系统看做一个模型-视图-控制器(MVC)架构,这个类代表的是模型。文本存储是中心对象,它知道所有的文本和属性信息。它只提供了两个存取器方法存取它们,并提供了另外两个方法来修改它们。后面我们将进一步了解它们。现在重要的是你得理解 NSTextStorage 是从它的父类 NSAttributedString 继承了这些方法。这就很清楚了,文本存储——从文本系统看来——仅仅是一个带有属性的字符串,以及几个扩展。这两者唯一的重大不同点是文本存储包含了一个方法来发送内容改变的通知。我们会马上介绍这部分内容。

  UITextView:堆栈的另一头是实际的视图。在 TextKit 中,文本视图有两个目的:第一,它是文本系统用来绘制的视图。文本视图它自己并不会做任何绘制;它仅仅提供一个供其它类绘制的区域。作为视图层级机构中唯一的组件,第二个目的是处理所有的用户交互。具体来说,文本视图实现 UITextInput 的协议来处理键盘事件,它为用户提供了一种途径来设置一个插入点或选择文本。它并不对文本做任何实际上的改变,仅仅将这些改变请求转发给刚刚讨论的文本存储。

  NSTextContainer:每个文本视图定义了一个文本可以绘制的区域。为此,每个文本视图都有一个文本容器,它精确地描述了这个可用的区域。在简单的情况下,这是一个垂直的无限相当大的矩形区域。文本被填充到这个区域,并且文本视图允许用户滚动它。然而,在更高级的情况下,这个区域可能是一个无限大的矩形。例如,当渲染一本书时,每一页都有最大的高度和宽度。文本容器会定义这个大小,并且不接受任何超出的文本。相同情况下,一幅图像可能占据了页面的一部分,文本应该沿着它的边缘重新排版。这也是由文本容器来处理的,我们会在后面的例子中看到这一点。

  NSLayoutManager:布局管理器是中心组件,它把所有组件粘合在一起:

  • 1、这个管理器监听文本存储中文本或属性改变的通知,一旦接收到通知就触发布局进程。
  • 2、从文本存储提供的文本开始,它将所有的字符翻译为字形(Glyph)(附注2).
  • 3、一旦字形全部生成,这个管理器向它的文本容器(们)查询文本可用以绘制的区域
  • 4、然后这些区域被行逐步填充,而行又被字形逐步填充。一旦一行填充完毕,下一行开始填充。
  • 5、对于每一行,布局管理器必须考虑断行行为(放不下的单词必须移到下一行)、连字符、内联的图像附件等等。
  • 6、当布局完成,文本的当前显示状态被设为无效,然后文本管理器将前面几步排版好的文本设给文本视图。

  CoreText:没有直接包含在 TextKit 中,CoreText 是进行实际排版的库。对于布局管理器的每一步,CoreText 被这样或那样的方式调用。它提供了从字符到字形的翻译,用它们来填充行,以及建议断字点。

使用示例:

        customLabel.text = "百度一下你就知道 http://www.baidu.com"

代码示例:

import UIKit

class JQLabel: UILabel {

     override var text: String?
{
didSet{
// 1.修改textStorage存储的内容
textStorage.setAttributedString(NSAttributedString(string: text!)) // 2.设置textStorage的属性
textStorage.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(), range: NSMakeRange(, text!.characters.count)) // 3.处理URL
self.URLRegex() // 2.通知layoutManager重新布局
setNeedsDisplay()
}
} // 如果是UILabel调用setNeedsDisplay方法, 系统会促发drawTextInRect
override func drawTextInRect(rect: CGRect) {
// 重绘
// 字形 ; 理解为一个小的UIView
/*
第一个参数: 指定绘制的范围
第二个参数: 指定从什么位置开始绘制
*/
layoutManager.drawGlyphsForGlyphRange(NSMakeRange(, text!.characters.count), atPoint: CGPointZero)
} override init(frame: CGRect) {
super.init(frame: frame)
setupSystem()
} required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSystem()
} private func setupSystem()
{
// 1.将layoutManager添加到textStorage
textStorage.addLayoutManager(layoutManager)
// 2.将textContainer添加到layoutManager
layoutManager.addTextContainer(textContainer)
} override func layoutSubviews() {
super.layoutSubviews() // 3.指定区域
textContainer.size = bounds.size
} // MARK: -懒加载
/*
只要textStorage中的内容发生变化, 就可以通知layoutManager重新布局
layoutManager重新布局需要知道绘制到什么地方, 所以layoutManager就会文textContainer绘制的区域
*/ // 专门用于存储内容的
// textStorage 中有 layoutManager
private lazy var textStorage = NSTextStorage() // 专门用于管理布局
// layoutManager 中有 textContainer
private lazy var layoutManager = NSLayoutManager() // 专门用于指定绘制的区域
private lazy var textContainer = NSTextContainer() func URLRegex()
{ // 1.创建一个正则表达式对象
do{
let dataDetector = try NSDataDetector(types: NSTextCheckingTypes(NSTextCheckingType.Link.rawValue)) let res = dataDetector.matchesInString(textStorage.string, options: NSMatchingOptions(rawValue: ), range: NSMakeRange(, textStorage.string.characters.count)) // 4取出结果
for checkingRes in res
{
let str = (textStorage.string as NSString).substringWithRange(checkingRes.range)
let tempStr = NSMutableAttributedString(string: str) // tempStr.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, str.characters.count))
tempStr.addAttributes([NSFontAttributeName: UIFont.systemFontOfSize(), NSForegroundColorAttributeName: UIColor.redColor()], range: NSMakeRange(, str.characters.count)) textStorage.replaceCharactersInRange(checkingRes.range, withAttributedString: tempStr)
}
}catch
{
print(error)
} } }

点击事件的处理:

import UIKit

class JQTextView: UITextView {

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        // 1.获取手指点击的位置
let touch = (touches as NSSet).anyObject()!
let point = touch.locationInView(touch.view) print(point) // 2.获取URL的区域
// 注意: 没有办法直接设置UITextRange的范围
let range = NSMakeRange(, )
// 只要设置selectedRange, 那么就相当于设置了selectedTextRange
selectedRange = range // 给定指定的range, 返回range对应的字符串的rect
// 返回数组的原因是因为文字可能换行
let array = selectionRectsForRange(selectedTextRange!) for selectionRect in array{
// let tempView = UIView(frame: selectionRect.rect)
// tempView.backgroundColor = UIColor.redColor()
// addSubview(tempView) if CGRectContainsPoint(selectionRect.rect, point)
{
print("点击了URL")
}
} }
}
 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
CGPoint pp = [self convertPoint:point toView:self.textView];
GPLink *touchingLink = [self touchingLinkWithPoint:pp]; if (touchingLink) {
[[NSNotificationCenter defaultCenter] postNotificationName:GPLinkDidSelectedNotification object:nil userInfo:@{GPLinkText : touchingLink.text}];
} [self touchesCancelled:touches withEvent:event];
}
- (GPLink *)touchingLinkWithPoint:(CGPoint)point
{
__block GPLink *touchingLink = nil;
[self.links enumerateObjectsUsingBlock:^(GPLink *link, NSUInteger idx, BOOL *stop) {
for (UITextSelectionRect *selectionRect in link.rects) {
if (CGRectContainsPoint(selectionRect.rect, point)) {
NSLog(@"选中%@",NSStringFromCGRect(selectionRect.rect));
touchingLink = link;
break;
}
}
}];
return touchingLink;
}

第一篇、Swift_Textkit的基本使用的更多相关文章

  1. 从0开始搭建SQL Server AlwaysOn 第一篇(配置域控)

    从0开始搭建SQL Server AlwaysOn 第一篇(配置域控) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www.cnb ...

  2. Python爬虫小白入门(四)PhatomJS+Selenium第一篇

    一.前言 在上一篇博文中,我们的爬虫面临着一个问题,在爬取Unsplash网站的时候,由于网站是下拉刷新,并没有分页.所以不能够通过页码获取页面的url来分别发送网络请求.我也尝试了其他方式,比如下拉 ...

  3. Three.js 第一篇:绘制一个静态的3D球体

    第一篇就画一个球体吧 首先我们知道Three.js其实是一个3D的JS引擎,其中的强大之处就在于这个JS框架并不是依托于JQUERY来写的.那么,我们在写这一篇绘制3D球体的文章的时候,应该注意哪些地 ...

  4. 深入学习jQuery选择器系列第一篇——基础选择器和层级选择器

    × 目录 [1]id选择器 [2]元素选择器 [3]类选择器[4]通配选择器[5]群组选择器[6]后代选择器[7]兄弟选择器 前面的话 选择器是jQuery的根基,在jQuery中,对事件处理.遍历D ...

  5. 【第一篇】ASP.NET MVC快速入门之数据库操作(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  6. Android基础学习第一篇—Project目录结构

    写在前面的话: 1. 最近在自学Android,也是边看书边写一些Demo,由于知识点越来越多,脑子越来越记不清楚,所以打算写成读书笔记,供以后查看,也算是把自己学到所理解的东西写出来,献丑,如有不对 ...

  7. 深入理解ajax系列第一篇——XHR对象

    × 目录 [1]创建对象 [2]发送请求 [3]接收响应[4]异步处理[5]实例演示 前面的话 ajax是asynchronous javascript and XML的简写,中文翻译是异步的java ...

  8. 深入理解javascript对象系列第一篇——初识对象

    × 目录 [1]定义 [2]创建 [3]组成[4]引用[5]方法 前面的话 javascript中的难点是函数.对象和继承,前面已经介绍过函数系列.从本系列开始介绍对象部分,本文是该系列的第一篇——初 ...

  9. 深入理解this机制系列第一篇——this的4种绑定规则

    × 目录 [1]默认绑定 [2]隐式绑定 [3]隐式丢失[4]显式绑定[5]new绑定[6]严格模式 前面的话 如果要问javascript中哪两个知识点容易混淆,作用域查询和this机制绝对名列前茅 ...

  10. 前端工程师技能之photoshop巧用系列第一篇——准备篇

    × 目录 [1]作用 [2]初始化 [3]常用工具[4]快捷键 前面的话 photoshop是前端工程师无法回避的一个软件,这个软件本身很强大,但我们仅仅需要通过这个工具来完成基本的切图工作即可.本文 ...

随机推荐

  1. 第十三章、学习 Shell Scripts 善用判断式

    善用判断式 利用 test 命令的测试功能 我要检查 /dmtsai 是否存在时,使用: [root@www ~]# test -e /dmtsai [root@www ~]# test -e /dm ...

  2. CSS构造模型

    div 边距 边框 定位 浮动 21.1 div 部分(division)---<div>元素,经常以div形式引用---是XHTML元素,用于定义XHTML文件中的区域. 1.添加div ...

  3. The Woman in Red Is Seen as a Threat by Other Wom

    The Woman in Red Is Seen as a Threat by Other Wom In the 1939 film classic The Women, much is made o ...

  4. 使用Go语言两三事

    使用Go语言两三事,在网上看到的总结的很不错哦,转自http://www.cnblogs.com/sevenyuan/archive/2013/02/27/2935887.html 一.channel ...

  5. hdu 5495 LCS 水题

    LCS Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5495 Descr ...

  6. POJ_1365_Prime_Land

    //懒得解释 #include <iostream> #include <cstring> #include <cmath> #include <cstdio ...

  7. java堆栈 (转)

     Java栈与堆 ----对这两个概念的不明好久,最终找到一篇好文,拿来共享 1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自己主动管理栈和堆, ...

  8. ios开发——笔记篇

    :开关 BOOL isopen = !isopen; //View @property (nonatomic, assign) BOOL open;//模型属性 self.group.open = ! ...

  9. 重现PHP Core的调用栈

        以前, 我曾经介绍过如何通过PHP的Core文件获取信息:如何调试PHP的Core之获取基本信息, 对于调用参数这块, 当时介绍的获取方法比较复杂. 于是今天我为PHP 5.4的.gdbini ...

  10. java_spring_List,Map,Properties,Set注入与遍历

    package com.dao.bean.www; import java.util.List; import java.util.Map; import java.util.Properties; ...