zoukankan      html  css  js  c++  java
  • iOS图文混排

    图文混排, 文本点击事件, 文本动画(不在讨论之内,可以通过对view来处理),如果是简单的操作,可以用UITextView来处理,当需要特殊的定制化的时候可以采用CoreText,它是一个强大的文本处理框架,支持所有文本排列相关的定制化操作,配合CoreGraphics可以实现图文混排功能。

    实现原理

    CoreText是一个底层的文本绘制框架,它真正绘制的其实只是文本部分,如果涉及到图片还是需要手动去的绘制的,它主要是通过对文本的段落样式,行样式,字体大小,样式配置信息统一搜集后,计算出它的layout再进行绘制,它主要包括以下几个关键类。

    1. CTFramesetter (排版)
    2. CFFrame (段落,框架)
    3. CFLine (行)
    4. CTRun (文字)
    5. CFTTypeSetter(排字)

    原点位置

    • CoreText中的文本原点位置和UIView是基于X轴承镜像对称,Y坐标相反

    Appkit->NSView: leftBottom
    UIKit->UIView: topRight
    CoreGraphic->Context: letBottom

    CoreText对象模型

    • CFAttributedStringRef: 属性字符串,用于存储所徐哟啊绘制额文字字符和属性

    • CTFramesetterRef: 对应的是CTFramesetter,通过CFAttributedStringRef进行初始化,它作为CTFrame的生产工厂,负责根据对应的Path生成对应的CTFrame

    • CTFrame: 可以通过CTFrameDraw函数直接绘制到Context上,在绘制之前可以通过CTLine进行一些参数的微调

    • CTLine: CTFrame内部是由多个CTLine组成,每个CTLine可以看作一行

    • CTRun: 或者叫做Glyph Run,每个CTLine是由多恶搞CTRun组成,CTRun是一组显示风格一致的文本(类似Flutter中的TextSpan),是一组有着相同attributes(属性)的字型集合体

    通常处理步骤

    • 获取当前的上下文对象
    • 翻转坐标系,Y轴对称
    • 创建AttributedString,转化为对应的CTFramesetterRef
    • 创建绘制区域: CGPathRef
    • 根据CTFramesetterRefCGPathRef创建CTFrame
    • CGFrameDraw绘制文字
    func layoutParagraph() {
               
            let context = UIGraphicsGetCurrentContext()!
               
               //1. 反转Y,Coregraphics的坐标系在坐下角
               context.translateBy(x: 0, y: self.bounds.size.height);
               context.scaleBy(x: 1.0, y: -1.0)
               context.textMatrix = CGAffineTransform.identity;
               
               //2. 创建路径
               let path = CGMutablePath();
               let rect = CGRect(x: 10.0, y: 10.0,  200.0, height: 200.0);
               path.addRect(rect)
               
               //3.创建`CFAttributedString`
               let data = "Hello, World! I know nothing in the world that has as much power as a word. Sometimes I write one, and I look at it, until it begins to shine.".withCString{ $0 }
               let cfString = CFStringCreateWithCString(kCFAllocatorDefault,data, CFStringBuiltInEncodings.UTF8.rawValue)
               let attrString =
               CFAttributedStringCreateMutable(kCFAllocatorDefault, 0)!;
               CFAttributedStringReplaceString(attrString, CFRangeMake(0, 0), cfString)
               
               //4.设置部分文本的属性
               let colorSpace = CGColorSpaceCreateDeviceRGB()
               let components = [CGFloat(0.0), CGFloat(0.3), CGFloat(0.3), CGFloat(0.8) ].withUnsafeBufferPointer{ $0 }
               let redColor = CGColor(colorSpace: colorSpace, components: components.baseAddress!)
               CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 12),
               kCTForegroundColorAttributeName, redColor);
               
               //5.创建文本布局对象
               let framesetter = CTFramesetterCreateWithAttributedString(attrString)
               
               //6. 绘制片段
               let frame = CTFramesetterCreateFrame(framesetter,
                                                    CFRangeMake(0,0), path, nil);
               //7.执行绘制
               CTFrameDraw(frame, context)
           }
    

    局部点击判断

    • 由于CoreText中的文本是基于CTFrame进行排版的,它包括了多个CTLine,所以很容易得到各个line的位置和大小,判断点击在不在某个line上,CTLine又可以进一步判断点击的文字是否在CTLine的指定坐标上,通过便利这个String的NSTextCheckingResult结果,根据Rang计算出文字的具体位置。

    图文混排

    • CoreText本身不支持图片绘制,图片绘制需要使用Core Graphics,CoreText只是通过CCTRun的设置为图片的绘制提供预留的空间,这个设置需要使用CTRunDelegate,CTRunDelegate作为CTRun相关属性或操作扩展的一个入口,使得我们可以对CTRun做一些自定义的行为。为图片留位置的方法就是加入一个空白的CTRun,自定义其ascent,descent,width等参数,使得绘制文本的时候留下空白位置给相应的图片。然后图片在相应的空白位置上使用Core Graphics接口进行绘制。

    • 使用CTRunDelegateCreate可以创建一个CTRunDelegate,它接收两个参数,一个是callbacks结构体,一个是所有callback调用的时候需要传入的对象。 callbacks的结构体为CTRunDelegateCallbacks,主要是包含一些回调函数,比如有返回当前run的ascent,descent,width这些值的回调函数,至于函数中如何鉴别当前是哪个run,可以在CTRunDelegateCreate的第二个参数来达到目的,因为CTRunDelegateCreate的第二个参数会作为每一个回调调用时的入参。

    参考链接

    CoreText Programming Guide: https://developer.apple.com/library/archive/documentation/StringsTextFonts/Conceptual/CoreText_Programming/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005533

    YYText: https://github.com/ibireme/YYText

  • 相关阅读:
    《SQL初学者指南》——第1章 关系型数据库和SQL
    《SQL初学者指南》——第1章 关系型数据库和SQL
    快讯:Oracle自治事务处理数据库发布和19c路线图
    NoReverseMatch: u'polls' is not a registered namespace
    Tomcat配置图片保存路径,图片不保存在项目路径下
    请慎用java的File#renameTo(File)方法
    sentinel monitor mymaster 10.10.17.200 6379 1 1个哨兵同意就切换
    静默错误:Oracle 数据库是如何应对和处理的 ?
    如何对Node.js默认下载路径进行修改
    “我卖一个群可以赚2万,但这个项目,死了!”
  • 原文地址:https://www.cnblogs.com/wwoo/p/ios-tu-wen-hun-pai.html
Copyright © 2011-2022 走看看