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

2020-07-28  本文已影响0人  ce2f22ad95cd

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?

}

上一篇下一篇

猜你喜欢

热点阅读