Swift 重構(gòu): UIAlertController 富文本鏈接點(diǎn)擊事件/用戶隱私協(xié)議彈窗

需求:

最近重構(gòu)項(xiàng)目代碼嘗試用 UIAlertController 實(shí)現(xiàn)富文本呈現(xiàn)及跳轉(zhuǎn)事件低千,過程是曲折的配阵,但結(jié)果是完美的。

Screenshot:

WechatIMG58.jpeg

核心源碼:

@objc func showAlertAgreement() {
    let title = "用戶協(xié)議和隱私政策"

    let linkDic = ["《用戶協(xié)議》": "http://*",
                   "《隱私政策》": "http://*",]

    let string = "\t用戶協(xié)議和隱私政策請(qǐng)您務(wù)必審值閱讀、充分理解 “用戶協(xié)議” 和 ”隱私政策” 各項(xiàng)條款棋傍,包括但不限于:為了向您提供即時(shí)通訊救拉、內(nèi)容分享等服務(wù),我們需要收集您的設(shè)備信息瘫拣、操作日志等個(gè)人信息近上。\n\t您可閱讀《用戶協(xié)議》和《隱私政策》了解詳細(xì)信息。如果您同意拂铡,請(qǐng)點(diǎn)擊 “同意” 開始接受我們的服務(wù);"

    let attributedText = NSAttributedString.create(string, textTaps: Array(linkDic.keys))
    let alertVC = UIAlertController(title: title, message: nil, preferredStyle: .alert)
        .addActionTitles([kTitleCancell, "同意"]) { vc, action in
            DDLog(action.title)
        }

    alertVC.setValue(attributedText, forKey: kAlertMessage)
    alertVC.messageLabel?.addGestureTap { reco in
        reco.didTapLabelAttributedText(linkDic) { text, url in
            DDLog("\(text), \(url ?? "_")")
        }
    }
    alertVC.present()
}

//2021-08-12 17:47:59.674000+0800 AlertSheetStudyController.swift.showAlertAgreement()[line 409]: 《用戶協(xié)議》, http://*
//2021-08-12 17:48:05.490000+0800 AlertSheetStudyController.swift.showAlertAgreement()[line 409]: 《隱私政策》, http://*

@objc public extension UIAlertController{

    private var subView5: UIView? {
        guard let subView1: UIView = self.view.subviews.first,
              let subView2: UIView = subView1.subviews.first,
              let subView3: UIView = subView2.subviews.first,
              let subView4: UIView = subView3.subviews.first,
              let subView5: UIView = subView4.subviews.first
              else { return nil }
        return subView5
    }

    var titleLabel: UILabel? {
        guard let _ = self.title,
              let subView5 = subView5,
              subView5.subviews.count > 2,
              let label = subView5.subviews[1] as? UILabel
              else { return nil }
        return label
    }

    var messageLabel: UILabel? {
        guard let subView5 = subView5
              else { return nil }
        let messageLabelIndex = self.title == nil ? 1 : 2
        if subView5.subviews.count > messageLabelIndex,
           let label = subView5.subviews[messageLabelIndex] as? UILabel
           {
            return label
        }
        return nil
    }
}

@objc public extension UITapGestureRecognizer {

    /// UILabel 富文本點(diǎn)擊(僅支持 lineBreakMode = .byWordWrapping)
    func didTapLabelAttributedText(_ linkDic: [String: String], action: @escaping (String, String?) -> Void) {
        assert(((self.view as? UILabel) != nil), "Only supports UILabel")
        guard let label = self.view as? UILabel,
              let attributedText = label.attributedText
              else { return }

        // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: CGSize.zero)
        let textStorage = NSTextStorage(attributedString: attributedText)
        // Configure layoutManager and textStorage
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)

        // Configure textContainer
        textContainer.lineFragmentPadding = 0.0
        textContainer.lineBreakMode = label.lineBreakMode
        textContainer.maximumNumberOfLines = label.numberOfLines

        let labelSize = label.bounds.size
        textContainer.size = labelSize

        // Find the tapped character location and compare it to the specified range
        let locationOfTouchInLabel = self.location(in: label)
        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        let textContainerOffset = CGPoint(x:(labelSize.width - textBoundingBox.size.width)*0.5 - textBoundingBox.origin.x,
                                        y:(labelSize.height - textBoundingBox.size.height)*0.5 - textBoundingBox.origin.y)
        let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x,
                                                   y: locationOfTouchInLabel.y - textContainerOffset.y)
        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer,
                                                          in: textContainer,                                                             fractionOfDistanceBetweenInsertionPoints: nil)

        //
        linkDic.forEach { e in
            let targetRange: NSRange = (attributedText.string as NSString).range(of: e.key)
            let isContain = NSLocationInRange(indexOfCharacter, targetRange)
            if isContain {
                action(e.key, e.value)
            }
        }
    }
}

github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市感帅,隨后出現(xiàn)的幾起案子斗锭,更是在濱河造成了極大的恐慌失球,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件实苞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡黔牵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門猾浦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陆错,“玉大人,你說我怎么就攤上這事金赦∫舸桑” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵夹抗,是天一觀的道長(zhǎng)绳慎。 經(jīng)常有香客問我,道長(zhǎng)漠烧,這世上最難降的妖魔是什么杏愤? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮沽甥,結(jié)果婚禮上声邦,老公的妹妹穿的比我還像新娘。我一直安慰自己摆舟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著恨诱,像睡著了一般媳瞪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上照宝,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天蛇受,我揣著相機(jī)與錄音,去河邊找鬼厕鹃。 笑死兢仰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的剂碴。 我是一名探鬼主播把将,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼忆矛!你這毒婦竟也來了察蹲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤催训,失蹤者是張志新(化名)和其女友劉穎洽议,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漫拭,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亚兄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了采驻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儿捧。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖挑宠,靈堂內(nèi)的尸體忽然破棺而出菲盾,到底是詐尸還是另有隱情,我是刑警寧澤各淀,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布懒鉴,位于F島的核電站,受9級(jí)特大地震影響碎浇,放射性物質(zhì)發(fā)生泄漏临谱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一悉默、第九天 我趴在偏房一處隱蔽的房頂上張望苟穆。 院中可真熱鬧唱星,春花似錦间聊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至飘言,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間热凹,已是汗流浹背泪电。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碟渺,地道東北人突诬。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像绒极,于是被迫代替她去往敵國(guó)和親蔬捷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容