UILabel显示HTML富文本,响应点击事件

html-css04

UILabel显示HTML富文本,响应点击事件,第1张

importFoundation

protocol HtmlLabelDelegate {

    funcclickUrl(url:NSURL)

    funcclickImage(image:UIImage)

}

class HtmlLabel: UILabel {

    //Mark --`TextKit` 的核心对象 绘制`textStorage`的文本内容

    /// 属性文本存储

    private lazy var textStorage = NSTextStorage()

    /// 负责文本`字形`布局 1.绘制背景  2.绘制Glyphs 字形 3.获取点中字符的索引

    private lazy var layoutManager = NSLayoutManager()

    /// 设定文本绘制的范围

    private lazy var textContainer = NSTextContainer()

    var delegate:HtmlLabelDelegate?

    var attachments:Array<AttachmentModel>= []

    // Mark: 一旦内容变化 需要让 textStorge 响应变化

    // Mark: --重写属性

    override var text: String?{

        didSet{

            // 重新准备文本内容

            prepareTextSystem()

        }

    }

    override var attributedText: NSAttributedString?{

        didSet{

            // 重新准备文本内容

            prepareTextSystem()

        }

    }

    // Mark: -- 构造函数

    overrideinit(frame:CGRect) {

        super.init(frame: frame)

      prepareTextSystem()

    }

    requiredinit?(coder aDecoder:NSCoder) {

      super.init(coder: aDecoder)

      prepareTextSystem()

    }

    // Mark: --交互

    overridefunctouchesBegan(_touches:Set, with event:UIEvent?) {

        guard let location = touches.first?.location(in:self)else{

           return

        }

        for r in attachments{

            if(r.rect?.contains(location))! {

                ifr.image!=nil{

                    print("click image")

                    break

                }else if r.url!=nil{

                    print("click url")

                    break

                }

            }else{

                print("没戳着")

            }

        }

    }

    override func drawText(in rect:CGRect) {

        letrange =NSRange(location:0, length:textStorage.length)

        ///绘制背景

        layoutManager.drawBackground(forGlyphRange: range, at:CGPoint())

        /// 绘制Glyphs 字形

        /// CGPoint():从原点绘制

        layoutManager.drawGlyphs(forGlyphRange: range, at:CGPoint())

    }

    override func layoutSubviews() {

        super.layoutSubviews()

        //指定绘制文本的区域

        textContainer.size = bounds.size

    }

}

private extension HtmlLabel{

    ///准备文本系统

    func prepareTextSystem(){

        // 0.开启交互

        isUserInteractionEnabled = true

        //1.准备文本内容

        prepareTextContent()

        //2.设置对象的关系

        textStorage.addLayoutManager(layoutManager)

        layoutManager.addTextContainer(textContainer)

    }

    /// 使用`textStorage`接管label内容

    func prepareTextContent(){

        ifletattributedText =attributedText{

            textStorage.setAttributedString(attributedText)

        }elseiflettext =text{

            textStorage.setAttributedString(NSAttributedString(string: text))

        }else{

            textStorage.setAttributedString(NSAttributedString(string: ""))

        }

        getAttachments()

    }

    func getAttachments(){

        if attributedText == nil {

            return

        }

        attributedText!.enumerateAttributes(in: NSRange(location: 0, length: attributedText!.length), options: NSAttributedString.EnumerationOptions.longestEffectiveRangeNotRequired, using: { (dic, range, stop) in

                    if dic.keys.contains(NSAttributedString.Key.attachment) {

                        let attacment:NSTextAttachment = dic[NSAttributedString.Key.attachment] as! NSTextAttachment

                        ifattacment.fileWrapper!=nil&&attacment.fileWrapper!.regularFileContents!=nil{

                            letrect =boundingRectForCharacterRange(range: range)

                            letattachmentModel =AttachmentModel()

                            attachmentModel.image=UIImage(data: attacment.fileWrapper!.regularFileContents!)

                            attachmentModel.rect= rect

                            attachments.append(attachmentModel)

                        }

                    }else if dic.keys.contains(NSAttributedString.Key.link) {

                        leturl:NSURL= dic[NSAttributedString.Key.link]as!NSURL

                        letrect =boundingRectForCharacterRange(range: range)

                        letattachmentModel =AttachmentModel()

                        attachmentModel.url= url

                        attachmentModel.rect= rect

                        attachments.append(attachmentModel)

                    }

                })

    }

    private func boundingRectForCharacterRange(range:NSRange) ->CGRect{

        textContainer.lineFragmentPadding = 0

        letglyphRange =layoutManager.characterRange(forGlyphRange: range, actualGlyphRange:nil)

        letrect =layoutManager.boundingRect(forGlyphRange: glyphRange, in:textContainer)

        returnrect

    }

}

class AttachmentModel {

    varimage:UIImage?

    varurl:NSURL?

    varrect:CGRect?

}

参考富文本:LayaAir下 HtmlDivElement的使用汇总 富文本HtmlDivElement的使用 HTML文本1.简单的Html属性设置:Bold、Font、FontSize、Color、下划线 示例如下: 2、获取Html文本的实际内容、获取html文本的实际宽高(contextWidth、contextHeight) 示例如下: 3、设置文本的水平居中对齐(align需要和width配合使用),换行( 换行需要有行高)、空格( ;) 【注意:目前不支持文本的垂直居中对齐,开发可以将(图片的高度-文本的高度)/2的值赋给文本的Y值,进行垂直居中对齐的替代设置】 示例如下: 4、实现超链接 示例如下: 5、实现html页面跳转 示例如下: 6、简单的图片显示 示例如下: 7、追加文本内容appendHtml 示例如下: 8、解决IOS手机上英文字母显示偏下的问题 在style样式中加垂直向上对齐valign:top属性 示例如下: 总结:以上的方法仅供参考,某些方法只是实现方式的一种,开发者也可以通过其他方式进行设置,如果有哪些方法没有涉及到的,欢迎开发者提出来,我们会陆续进行补充! 9.换行 设置style.width会自动换行,手动换行需要在span标签后添加br 10.描边 参考 HTMLDivElement文本字体描边怎么弄呢11.斜体 不支持 12.滚动条 参考 建议官方针对HtmlDIVElement出和TextArea相关的功能htmldivelement组件是没有滚动条的,它不具备输入功能,不能编辑,有点类似flash的htmltext文本可以实现富文本图文混排。textarea是支持滚动条的文本输入框,内容本身不能存在图片,不支持文本局部链接。 可以把htmldivelement放到一个容器里,然后把这个容器放到panel里,panel是支持滚动条的,这样可以通过内容的填充显示出滚动条! 13.参考示例