最详细TextKit分析

1、粗略的了解一下TextKit

     在iOS开发中,处理文本的视图控件主要有4中,UILabel,UITextField,UITextView和UIWebView。其中UILabel与UITextField相对简单,UITextView是功能完备的文本布局展示类,通过它可以进行复杂的富文本布局,UIWebView主要用来    加载网页或者pdf文件,其可以进行HTML,CSS和JS等文件的解析。

        TextKit是一个偏上层的开发框架,在iOS7以上可用,使用它开发者可以方便灵活处理复杂的文本布局,满足开发中对文本布局的各种复杂需求。TextKit实际上是基于CoreText的一个上层框架,其是面向对象的,如果TextKit中提供的API无法满足需求,可以使用CoreText中的API进行更底层的开发。

        官方文档中的一张图片很确切,经常会被用来描述TextKit框架在iOS系统文本渲染中所处的位置。

最详细TextKit分析_第1张图片

2、TextKit框架的结构

界面在进行文本的渲染时,有下面几个必要条件:

1.要渲染展示的内容。

2.将内容渲染在某个视图上。

3.内容渲染在视图上的尺寸位置和形状。

在TextKit框架中,提供了几个类分别对应处理上述的必要条件:

1.NSTextStorage对应要渲染展示的内容。

2.UITextView对应要渲染的视图。

3.NSTextContainer对应渲染的尺寸位置和形状信息。

除了上述3个类之外,TextKit框架中的NSLayoutManager类作为协调者来进行布局操作。

上述关系如下图所示:

最详细TextKit分析_第2张图片



3、使用TextKit进行文本布局流程

前面都是一些基本介绍,直接摘录云栖社区大神的,TextKit主要用于更精细的处理文本布局以及进行复杂的图文混排布局,使用TextKit进行文本的布局展示十分繁琐,首先需要将显示内容定义为一个NSTextStorage对象,之后为其添加一个布局管理器对象NSLayoutManager,在NSLayoutManager中,需要进行NSTextContainer的定义,定义多了NSTextContainer对象则会将文本进行分页。最后,将要展示的NSTextContainer绑定到具体的UITextView视图上。也就是说我们可以通过使用TextKit完全的控制每一个字形的展示位置以及样式。

下图是他们的之间关系:

最详细TextKit分析_第3张图片

下面根据这张图谈一谈我的理解:NSTextStorage对象保存着要展示的内容,文字,图片。我认为最重要的一个类是NSLayoutManager,他管理着每一个字符的显示。NSTextContainer其实是管理着每一行字形的布局之后通过绑定TextView一行一行的绘制展现出来文字的,当然底层渲染使用的都是coreText。

这样我们是不是可以通过修改NSTextContainer显示区域,来改变文本的显示相撞,比喻显示为一个三角形、圆形等。答案当然是可以的,我们需要重写NSTextContainer里面的

override func lineFragmentRect(forProposedRect proposedRect: CGRect, at characterIndex: Int, writingDirection baseWritingDirection: NSWritingDirection, remaining remainingRect: UnsafeMutablePointer<CGRect>?) -> CGRect


这个方法是什么意思呢?官方文档那个解释:就是返回每行文本绘制的rect,这样我们改变rect的point就可以实现圆形文本了。

    override func lineFragmentRect(forProposedRect proposedRect: CGRect, at characterIndex: Int, writingDirection baseWritingDirection: NSWritingDirection, remaining remainingRect: UnsafeMutablePointer<CGRect>?) -> CGRect {

        let size  = self.size

        let rect = super.lineFragmentRect(forProposedRect: proposedRect, at: characterIndex, writingDirection: baseWritingDirection, remaining: remainingRect)

        

        let radius = fmin(size.width, size.height)/2

        let ypos = fabs((rect.origin.y + rect.size.height/2) - radius)

        let width = (ypos < radius) ? 2 * sqrt(radius * radius - ypos * ypos) : 0.0

      let finalRect = CGRect.init(x: rect.origin.x + radius - width/2.0, y: rect.origin.y, width: width, height: rect.size.height)

        

        return finalRect

    }

这样我们把我们textView的container替换为我们自定义的,就可以实现一个圆形的文本。最详细TextKit分析_第4张图片

当然我们也可以去修改NSLayoutManager,现在我们每一行文字都是整齐的排列,那么我们可以修改每个字符的位置,让其斜线排列。

最详细TextKit分析_第5张图片

 override func draw(_ rect: CGRect) {

        // 获取对应的字型的位置

        var range = NSRange.init(location: 0, length: 0)

        _ = layoutManager.lineFragmentRect(forGlyphAt: 0, effectiveRange: &range)

        

        for glyIndex in range.location ... (range.location + range.length - 1) {

            let point = layoutManager.location(forGlyphAt: glyIndex)

            print(point)

            // 绘制文字

            self.layoutManager.drawGlyphs(forGlyphRange: NSRange.init(location: glyIndex, length: 1), at: CGPoint.init(x: 10, y: 20 * glyIndex))

        }

    }

TextKit的大概使用就是这样的,NSLayoutManager里面很多方法,灵活运用可以做出很酷炫的效果。






















你可能感兴趣的:(iOS-开发)