swift 帶有復(fù)制功能的 UILabel

該博客同步于 <swift 帶復(fù)制功能的 Label | AndyCuiの博客>

產(chǎn)品需求需要對(duì) UILabel 展示的文本進(jìn)行復(fù)制操作,針對(duì)這一需求想出了兩種實(shí)現(xiàn)方式: 1.自定義控件,添加復(fù)制功能. 2.使用 UItextView 實(shí)現(xiàn).

通過(guò)自定義 UILabel 的子類(lèi)實(shí)現(xiàn)

  • 創(chuàng)建 YTTCopyLabel, 使其繼承于 UILabel.
class YTTCopyLabel: UILabel {
}
  • 使 YTTCopyLabel 可以進(jìn)行交互, 添加長(zhǎng)按手勢(shì)使其觸發(fā)復(fù)制事件

override var canBecomeFirstResponder: Bool { return true }

override func awakeFromNib() {
    super.awakeFromNib()
    setup()
}

override init(frame: CGRect) {
    super.init(frame: frame)
    setup()
}

private func setup() {
    self.isUserInteractionEnabled = true
    let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(_:)))
    self.addGestureRecognizer(longPressGestureRecognizer)
}
  • 在長(zhǎng)按事件中實(shí)現(xiàn)復(fù)制功能
    使用 UIMenuController 彈出復(fù)制菜單.使用簡(jiǎn)介
@objc private func longPressAction(_ sender: UIGestureRecognizer) {

    guard sender.state == .began else {
    return
    }

    // 變?yōu)榈谝豁憫?yīng)者
    self.becomeFirstResponder()

    // 菜單控制器
    let menuController = UIMenuController.shared
    // 復(fù)制 item
    let copyItem = UIMenuItem(title: "復(fù)制", action: #selector(copyText))
    // 添加 item 到 menu 控制器
    menuController.menuItems = [copyItem]
    // 設(shè)置菜單控制器點(diǎn)擊區(qū)域?yàn)楫?dāng)前控件 bounds
    menuController.setTargetRect(self.bounds, in: self)
    // 菜單顯示器可見(jiàn)
    menuController.setMenuVisible(true, animated: true)

}
  • 確認(rèn) label 具有的操作能力
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if action == #selector(copyText) {
        return true
    }
    return false
}
  • 實(shí)現(xiàn)將 label 內(nèi)容放到剪切板
@objc private func copyText() {
    UIPasteboard.general.string = self.text
}
  • 在需要的地方使用
let label = YTTCopyLabel(frame: CGRect(x: 20, y: 100, width: self.view.frame.width - 40, height: 30))

運(yùn)行效果如下:
YTTCopyLabel.swift

通過(guò)設(shè)置 UITextView 的屬性實(shí)現(xiàn)

UITextView 本身就有復(fù)制的功能,他有兩個(gè)屬性车海,一個(gè)可控制其是否編輯,一個(gè)是可控制其是否可選,只需將其可編輯設(shè)為 false

isEditable = false
  • 創(chuàng)建 YTTCustomTextView,使其繼承與 UITextView
class YTTCustomTextView: UITextView {
}
  • 重寫(xiě)父類(lèi)方法,使其使其編輯功能
@IBInspectable
var isAutoLayout: Bool = true  // 是否是自適應(yīng)布局

override func awakeFromNib() {
    super.awakeFromNib()
    setup()
}

override init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    setup()
}

private func setup() {
    self.isEditable = false
    self.isScrollEnabled = false // 設(shè)為 false 可自適應(yīng)
}
  • 重寫(xiě)屬性 text 與 attributedText, 進(jìn)行自適應(yīng)布局
override var text: String! {
    get {
        return super.text
    }
    set {
        super.text = newValue
        if !isAutoLayout {
            let width = self.bounds.width - (self.contentInset.left + self.contentInset.right + self.textContainerInset.left + self.textContainerInset.right + self.textContainer.lineFragmentPadding * 2)
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineBreakMode = self.textContainer.lineBreakMode
            let wordHeight = (self.text as NSString).boundingRect(with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [.font : self.font!, .paragraphStyle: paragraphStyle ], context: nil).height + self.textContainerInset.top + self.textContainerInset.bottom + self.textContainer.lineFragmentPadding * 2 + self.contentInset.top + self.contentInset.bottom
            let rect = CGRect(x: self.frame.minX, y: self.frame.minY, width: width, height: wordHeight)
            self.frame = rect
        }
    }
}

override var attributedText: NSAttributedString! {
    get {
        return super.attributedText
    }
    set {
        super.attributedText = newValue
        if !isAutoLayout {
            let width = self.bounds.width - (self.contentInset.left + self.contentInset.right + self.textContainerInset.left + self.textContainerInset.right + self.textContainer.lineFragmentPadding * 2)
            let wordHeight = newValue.boundingRect(with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil).height + self.textContainerInset.top + self.textContainerInset.bottom + self.textContainer.lineFragmentPadding * 2 + self.contentInset.top + self.contentInset.bottom
            let rect = CGRect(x: self.frame.minX, y: self.frame.minY, width: width, height: wordHeight)
            self.frame = rect
        }
    }
}
  • 判斷屏幕點(diǎn)擊事件是否在本視圖,不是取消選中狀態(tài)
// 設(shè)置點(diǎn)擊空白取消選中效果
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    // 判斷點(diǎn)擊點(diǎn)是否在本視圖
    if !self.point(inside: point, with: event) {
        self.selectedRange = NSMakeRange(0, 0) // 設(shè)置為 NSMakeRange(0, 0) 取消選中效果
    }
    return super.hitTest(point, with: event)
}

YTTCustomTextView

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市撞羽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孵奶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蜡峰,警方通過(guò)查閱死者的電腦和手機(jī)了袁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)湿颅,“玉大人载绿,你說(shuō)我怎么就攤上這事⌒ぞ簦” “怎么了卢鹦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)劝堪。 經(jīng)常有香客問(wèn)我冀自,道長(zhǎng),這世上最難降的妖魔是什么秒啦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任熬粗,我火速辦了婚禮,結(jié)果婚禮上余境,老公的妹妹穿的比我還像新娘驻呐。我一直安慰自己灌诅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布含末。 她就那樣靜靜地躺著猜拾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪佣盒。 梳的紋絲不亂的頭發(fā)上挎袜,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音肥惭,去河邊找鬼盯仪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蜜葱,可吹牛的內(nèi)容都是我干的全景。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼牵囤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼爸黄!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起揭鳞,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤馆纳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后汹桦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鉴裹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年舞骆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片径荔。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡督禽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出总处,到底是詐尸還是另有隱情狈惫,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布鹦马,位于F島的核電站胧谈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏荸频。R本人自食惡果不足惜菱肖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望旭从。 院中可真熱鬧稳强,春花似錦场仲、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至褒繁,卻和暖如春亦鳞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背澜汤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工蚜迅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人俊抵。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓谁不,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親徽诲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刹帕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱(chēng)項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,980評(píng)論 3 119
  • 四月四谎替,十月十 十四是四十偷溺,四十是十四 一個(gè)選擇有一種生活可能 患者人生,文案世界 慢慢走向策劃人生钱贯,接近設(shè)計(jì)世界...
    世界患者閱讀 191評(píng)論 0 0
  • 此時(shí)此刻者坐在沙發(fā)上挫掏,在等待十點(diǎn)到來(lái)好去學(xué)游泳,我聽(tīng)到窗外的青蛙秩命,和蛤蟆在叫尉共,聲音很有規(guī)律,喂兒哇喂兒哇弃锐,吱吱的叫...
    水玲瓏英子閱讀 185評(píng)論 1 2
  • 本期話(huà)題是由我們的讀者提出來(lái)的霹菊。 關(guān)于分手后還能不能做朋友剧蚣? 分手后還要不要聯(lián)系? 等情感話(huà)題旋廷。 最近鸠按,小編我就此...
    紫柴子閱讀 389評(píng)論 0 2
  • “我們新疆好地方,麥穗金黃稻花香天山南北好風(fēng)光……“這是一首耳熟能詳?shù)男陆枨牡猓赃@首歌曲作為開(kāi)頭待诅,告訴大家我來(lái)自...
    安琪爾珂閱讀 166評(píng)論 0 0