Swift中UILabel添加可點(diǎn)擊字

import UIKit

//設(shè)置字體大小
var TAP_FONT:CGFloat = 14
//設(shè)置字體顏色
var TAP_COLOR:UIColor = UIColor.black
class XCTapLabel: UILabel{
    var specialStrings:[String]?
    lazy var specialRange:[NSRange] = []
    //行間距
    var line_Spacing:CGFloat = 2.0
    var reback:((String)->Void)?
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.font = adapterFont(font: TAP_FONT)
        self.textColor = TAP_COLOR     
        self.numberOfLines = 0
        self.isUserInteractionEnabled = true
        self.backgroundColor = .clear
        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapAction)))//給label添加點(diǎn)擊事項(xiàng)
        let longGes:UILongPressGestureRecognizer = UILongPressGestureRecognizer()
        longGes.minimumPressDuration = 0.5
        longGes.addTarget(self, action: #selector(longTap))
        self.addGestureRecognizer(longGes)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    deinit {
        //移除觀察者
        NotificationCenter.default.removeObserver(self)
    }
}

有長按label保存字體的需求可以加上

extension XCTapLabel{
  @objc func longTap(sender:UILongPressGestureRecognizer){
      if sender.state == .began{
          self.backgroundColor = UIColor.grayValue(value: 220)
          self.becomeFirstResponder()
          let menu = UIMenuController.shared
        
          //設(shè)置自定義菜單
          menu.menuItems = [UIMenuItem.init(title: "復(fù)制", action: #selector(xcCopy)) ]
          //菜單顯示位置
          menu.setTargetRect(self.bounds, in: self)
          //顯示菜單
          menu.setMenuVisible(true, animated: true)
          NotificationCenter.default.addObserver(self, selector: #selector(menuAction), name: UIMenuController.didHideMenuNotification, object: nil)
      }
  }
  @objc private func menuAction(){
      self.backgroundColor = UIColor.grayValue(value: 244)
      self.resignFirstResponder()
  }
  @objc private func xcCopy(){
      self.backgroundColor = UIColor.grayValue(value: 244)
      UIPasteboard.general.string = self.text
  }
  //MARK: 返回懸浮菜單中可以顯示的選項(xiàng)
  override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
      if action == #selector(xcCopy){
          return true
      }
      return false
  }
}

單擊響應(yīng),核心代碼

extension XCTapLabel{
    @objc func tapAction(tapGesture:UITapGestureRecognizer){
        //可變字符為空,則沒有點(diǎn)擊效果
        if self.attributedText == nil {
            return
        }
        //點(diǎn)擊的坐標(biāo)
        let position = tapGesture.location(in: self)
        //段落樣式
        let paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineBreakMode = NSLineBreakMode.byWordWrapping
        paragraphStyle.lineSpacing = 2
        //字體樣式
        let font:UIFont = UIFont.systemFont(ofSize: TAP_FONT)
        //新增字體樣式
        let newAttStyle:[NSAttributedString.Key:Any] = [NSAttributedString.Key.font:font,NSAttributedString.Key.paragraphStyle:paragraphStyle]
    
        //要根據(jù)設(shè)置的paragraphStyle來計(jì)算高度艳汽,否則計(jì)算的不準(zhǔn)確层皱,沒有計(jì)算行間距,CTFrameGetLines計(jì)算函數(shù)為0
        if let attText:NSMutableAttributedString = self.attributedText as? NSMutableAttributedString{
           attText.addAttributes(newAttStyle, range: NSMakeRange(0, attText.length))
        
           //CTFramesetter 是使用 Core Text 繪制時最重要的類涕烧。它管理您的字體引用和文本繪制幀鹊杖。
           let framesetter:CTFramesetter = CTFramesetterCreateWithAttributedString(attText)
           //貝塞爾路徑的尺寸
           let path:UIBezierPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
           //通過CTFramesetter獲取尺寸
           let ctframe:CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path.cgPath, nil)
           //通過CTFrame獲取有多少行的數(shù)組
           let lines:CFArray = CTFrameGetLines(ctframe)
           //行組的count
           let lineCount:CFIndex = CFArrayGetCount(lines)
           //獲取label的高度,width是已知的
           let height:CGFloat = self.sizeThatFits(CGSize(width: self.width, height: 9999)).height
           //計(jì)算每行有多高
           let lineHeight:CGFloat = height/CGFloat(lineCount)
           //獲取點(diǎn)擊的行數(shù)
           let lineIndex:Int = Int(position.y / lineHeight)
           //點(diǎn)擊的點(diǎn)
            let clickPoint:CGPoint = CGPoint(x: position.x, y: lineHeight - position.y)
            if lineIndex < lineCount {
                let clickLine:CTLine = unsafeBitCast(CFArrayGetValueAtIndex(lines, lineIndex), to: CTLine.self)
                let startIndex:CFIndex = CTLineGetStringIndexForPosition(clickLine, clickPoint)
                var content:String = ""
                for range in specialRange{
                    if startIndex >= range.location && startIndex <= range.location + range.length {
                        if let string:String = self.attributedText?.string{
                            let str = (string as NSString).substring(with: range)
                            content = str
                        }
                    }
                }
                self.reback?(content)
            }
        }
    }
    func setSpecialStrings(specialString:[String]?,attriString:NSAttributedString) -> Void{
        specialRange = []
        let string:String = attriString.string
        if let array:[String] = specialString{
            for str in array{
                let range:NSRange = (string as NSString).range(of: str)
                specialRange.append(range)
            }
        }
    }
}

======================具體用法======================
數(shù)據(jù)模型,這里面做富文本字體處理以及高度計(jì)算

class attModel: Mappable {
    //計(jì)算屬性,height作為tableview的DataSource中行高,過程中賦值給富文本字符串(attString)以及可點(diǎn)擊字符串?dāng)?shù)組(specialString)
    var height:CGFloat{
        let attStr:NSMutableAttributedString = NSMutableAttributedString()
        let label:UILabel = UILabel()
        label.numberOfLines = 0
        //這個是單人:張三:我真帥
        if self.to_nickname ?? "" == ""{
            let userStr:String = self.nickname ?? ""
            let attStr1:NSMutableAttributedString = XChandyAttributeString(str: userStr, font: 14, color: MAIN_COLOR)
            let contentStr:String = " : " + (self.lower_com_content ?? "")
            let attStr2:NSMutableAttributedString = XChandyAttributeString(str: contentStr, font: 14, color: UIColor.grayValue(value: 88))
            attStr.append(attStr1)
            attStr.append(attStr2)
            specialString = [userStr]
            attString = attStr
            label.attributedText = attStr
        }else{
            ///這個是有回復(fù)人的:張三回復(fù)李四:我真帥
            let userStr:String = self.nickname ?? ""
            let contentStr:String = " : " + (self.lower_com_content ?? "")
            let toSt:Stringr = self.to_nickname ?? ""
            let attStr1:NSMutableAttributedString = XChandyAttributeString(str: userStr, font: TAP_FONT, color: MAIN_COLOR)
            let attStr2:NSMutableAttributedString  = XChandyAttributeString(str: "回復(fù)", font: TAP_FONT, color: UIColor.grayValue(value: 88))
            let attStr3:NSMutableAttributedString  = XChandyAttributeString(str: toStr, font: TAP_FONT, color: MAIN_COLOR)
            let attStr4:NSMutableAttributedString  = XChandyAttributeString(str: contentStr, font: TAP_FONT, color: UIColor.grayValue(value: 88))
            attStr.append(attStr1)
            attStr.append(attStr2)
            attStr.append(attStr3)
            attStr.append(attStr4)
            specialString = [userStr,toStr]
            attString = attStr
            label.attributedText = attStr
        }
        let size:CGSize = label.sizeThatFits(CGSize(width: SCREEN_WIDTH-adapterWidth(70), height: 9999))
        return size.height+2     //加2是因?yàn)橛袝r候獲取不到行數(shù)
    }
    var attString:NSMutableAttributedString?
    var specialString:[String]?
    //json數(shù)據(jù)
    var nickname:String?
    var lower_com_content:String?
    var to_nickname:String?
    var toid:Int?
    var uid:Int?
    required init?(map: Map){}
    func mapping(map: Map){
        nickname <- map["nickname"]
        lower_com_content <- map["lower_com_content"]
        to_nickname <- map["to_nickname"]
        toid <- map["toid"]
        uid <- map["uid"]
    }
}

初始化及回調(diào)

let label:XCTapLabel = XCTapLabel()
label.reback = {[weak self] string in
//string就是點(diǎn)擊的字
}

var model:attModel?{
    didSet{
        tapLabel.frame = CGRect(x: adapterWidth(5), y: adapterWidth(5), width: SCREEN_WIDTH-adapterWidth(70), height: 0)
        //調(diào)用model?.height為了給attString以及setSpecialStrings賦值,不然兩者無值
        let height:CGFloat = model?.height ?? 0
        tapLabel.attributedText = model?.attString
        tapLabel.setSpecialStrings(specialString: model?.specialString, attriString:model?.attString ?? NSMutableAttributedString(string: ""))
        tapLabel.height = height
    }
}

看都看了,碼個代碼也不容易,留個小心心嘛~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捺氢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子口渔,更是在濱河造成了極大的恐慌饺窿,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沈矿,死亡現(xiàn)場離奇詭異上真,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)羹膳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門睡互,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事就珠】芸牵” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵嗓违,是天一觀的道長。 經(jīng)常有香客問我图贸,道長蹂季,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任疏日,我火速辦了婚禮偿洁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沟优。我一直安慰自己涕滋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布挠阁。 她就那樣靜靜地躺著宾肺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侵俗。 梳的紋絲不亂的頭發(fā)上锨用,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音隘谣,去河邊找鬼增拥。 笑死,一個胖子當(dāng)著我的面吹牛寻歧,可吹牛的內(nèi)容都是我干的掌栅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼码泛,長吁一口氣:“原來是場噩夢啊……” “哼猾封!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起噪珊,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤忘衍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后卿城,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枚钓,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年瑟押,在試婚紗的時候發(fā)現(xiàn)自己被綠了搀捷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嫩舟,靈堂內(nèi)的尸體忽然破棺而出氢烘,到底是詐尸還是另有隱情,我是刑警寧澤家厌,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布播玖,位于F島的核電站,受9級特大地震影響饭于,放射性物質(zhì)發(fā)生泄漏蜀踏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一掰吕、第九天 我趴在偏房一處隱蔽的房頂上張望果覆。 院中可真熱鬧,春花似錦殖熟、人聲如沸局待。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钳榨。三九已至,卻和暖如春纽门,著一層夾襖步出監(jiān)牢的瞬間重绷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工膜毁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昭卓,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓瘟滨,卻偏偏與公主長得像候醒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杂瘸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

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

  • 1倒淫、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,980評論 3 119
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,751評論 1 92
  • 記錄一下败玉,elasticsearch/lucene關(guān)于文檔與query之間相關(guān)性的計(jì)算方式敌土,目錄如下, Lucen...
    chenfh5閱讀 4,732評論 1 7
  • 寫了些東西才發(fā)現(xiàn)运翼,自己的文筆真的很差返干,有許多需要改進(jìn)提升的地方,于是就想找個師傅血淌,報(bào)個寫作培訓(xùn)班什么的矩欠〔破剩可是選來選...
    淇畔芷影閱讀 251評論 0 2
  • 苻丕率領(lǐng)鄴城百姓準(zhǔn)備離開的路線,正是十五年前王猛率領(lǐng)前秦軍隊(duì)攻滅前燕的道路癌淮,此時卻成了苻丕撤退的道路躺坟,不知道三十歲...
    寒七琪閱讀 352評論 0 1