運(yùn)用Runtime擴(kuò)大UIButton點(diǎn)擊區(qū)域

了解事件響應(yīng)鏈的同學(xué)應(yīng)該知道hitTestpoint方法遏匆,我們先來簡單回顧一下

hitTest

內(nèi)部實(shí)現(xiàn)

func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    // 1.判斷當(dāng)前控件能否接收事件
    if isUserInteractionEnabled == false || hidden == true || alpha <= 0.01 {
        return nil
    }
    // 2. 判斷點(diǎn)在不在當(dāng)前控件
    if self.point(inside: point, with: event) == false {
        return nil
    }
        // 3.從后往前遍歷自己的子控件
    let count: Int = subviews.count
    var i = count - 1
    while i >= 0 {
        let childView: UIView? = subviews[i]
            // 把當(dāng)前控件上的坐標(biāo)系轉(zhuǎn)換成子控件上的坐標(biāo)系
        let childP: CGPoint = convert(point, to: childView)
        let fitView: UIView? = childView?.hitTest(childP, with: event)
        if fitView != nil {
            // 尋找到最合適的view
            return fitView
        }
        i -= 1
    }
    // 循環(huán)結(jié)束,表示沒有比自己更合適的view  
    return self
}

總結(jié)

  • 作用:去尋找最適合的View
  • 調(diào)用:當(dāng)一個(gè)事件傳遞給當(dāng)前View,就會(huì)調(diào)用
  • 返回值:返回的是誰,誰就是最適合的View(就會(huì)調(diào)用最適合的View的touch方法)

point

open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        //   如果返回false就代表泥张,當(dāng)前點(diǎn)不在紅色view(self)上面初厚,那么當(dāng)我們確實(shí)點(diǎn)擊紅絲view趣钱,紅色view也不會(huì)響應(yīng)事件。
        //   return false;
        
        //如果返回true就代表,當(dāng)前點(diǎn)在紅色view(self)上面,那么即使我們沒有點(diǎn)擊紅絲view羔味,紅色view也會(huì)響應(yīng)事件。
        
}

總結(jié)

  • 作用:判斷當(dāng)前點(diǎn)在不在它調(diào)用View,(誰調(diào)用pointInside,這個(gè)View就是誰)
  • 調(diào)用:它是在hitTest方法當(dāng)中調(diào)用的
  • 注意:point點(diǎn)必須得要跟它方法調(diào)用者在同一個(gè)坐標(biāo)系里面

究竟什么時(shí)候重寫hitTest钠右,什么時(shí)候重寫point赋元?

很多情況下hitTest和pointInside方法任選其一都可以實(shí)現(xiàn)某個(gè)功能,比如在屏蔽中飒房,point返回false可以實(shí)現(xiàn)的話们陆,都可以用hitTest返回nil代替。
但是情屹,hitTest更強(qiáng)大。因?yàn)閜oint在一般情況下其內(nèi)部頂多只能根據(jù)情況判斷怎么返回false杂腰,屏蔽掉自己和子控件的事件響應(yīng)垃你。所以只要是想保留子控件對(duì)觸摸事件響應(yīng),屏蔽其父控件的響應(yīng)喂很,單獨(dú)重寫point無法辦到惜颇,必須要重寫hitTest方法。
觸摸事件原本該由某個(gè)view響應(yīng)少辣,現(xiàn)在你不想讓它處理而讓別的控件處理凌摄,那么就應(yīng)該在該view內(nèi)重寫hitTest或point方法。

運(yùn)用Runtime擴(kuò)大UIButton點(diǎn)擊區(qū)域

根據(jù)上面的介紹可以知道通過在UIButton的extension中重寫hitTestpoint漓帅,下面是簡單實(shí)現(xiàn)

extension UIButton {
    
    private struct cs_associatedKeys {
        
        static var topKey = "cs_topKey"
        static var rightKey = "cs_rightKey"
        static var bottomKey = "cs_bottomKey"
        static var leftKey = "cs_leftKey"
        static var marginKey = "cs_marginKey"
    }
    
    
    //方法一
    func setEnlargeEdgeWith(top: CGFloat, right: CGFloat, bottom: CGFloat, left : CGFloat) {
        
        objc_setAssociatedObject(self, &cs_associatedKeys.topKey, top, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        objc_setAssociatedObject(self, &cs_associatedKeys.rightKey, right, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        objc_setAssociatedObject(self, &cs_associatedKeys.bottomKey, bottom, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        objc_setAssociatedObject(self, &cs_associatedKeys.leftKey, left, .OBJC_ASSOCIATION_COPY_NONATOMIC)
    }
    
    private var enlargedRect: CGRect {
        
        let topEdge = objc_getAssociatedObject(self, &cs_associatedKeys.topKey) as? CGFloat
        let rightEdge = objc_getAssociatedObject(self, &cs_associatedKeys.rightKey) as? CGFloat
        let bottomEdge = objc_getAssociatedObject(self, &cs_associatedKeys.bottomKey) as? CGFloat
        let leftEdge = objc_getAssociatedObject(self, &cs_associatedKeys.leftKey) as? CGFloat
        
        guard let top = topEdge, let right = rightEdge, let botton = bottomEdge, let left = leftEdge else {
            return bounds
        }
        
        return CGRect(x: CGFloat(bounds.origin.x - left), y: CGFloat(bounds.origin.y - top), width: CGFloat(bounds.size.width + left + right), height: CGFloat(bounds.size.height + top + botton))
    }
    
    
    
    open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        
        let rect = self.enlargedRect
        if rect.equalTo(bounds) {
            return super.hitTest(point, with: event)
        }
        return rect.contains(point) ? self : nil
    }
    
    
    
    //方法二
    var margin: CGFloat{
        get {
            if let accpetEventInterval = objc_getAssociatedObject(self, &cs_associatedKeys.marginKey) as? CGFloat {
                return accpetEventInterval
            }
            return 0.0
        }
        set {
            objc_setAssociatedObject(self, &cs_associatedKeys.marginKey, newValue as CGFloat, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        
        var bounds = self.bounds
        bounds = bounds.insetBy(dx: -margin, dy: -margin)
        return bounds.contains(point)
    }
    
    
    
}

使用

        let btn = UIButton()
        btn.frame = CGRect(x: 100, y: 100, width: 40, height: 40)
        //方法一
//        btn.setEnlargeEdgeWith(top: 100, right: 100, bottom: 100, left: 100)
        //方法二
        btn.margin = 100
        btn.backgroundColor = UIColor.red
        btn.addTarget(self, action: #selector(ViewController.didTap), for: UIControlEvents.touchUpInside)
        self.view.addSubview(btn)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锨亏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子忙干,更是在濱河造成了極大的恐慌器予,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捐迫,死亡現(xiàn)場離奇詭異乾翔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)施戴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門反浓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萌丈,“玉大人,你說我怎么就攤上這事雷则×疚恚” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵巧婶,是天一觀的道長乾颁。 經(jīng)常有香客問我,道長艺栈,這世上最難降的妖魔是什么英岭? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮湿右,結(jié)果婚禮上诅妹,老公的妹妹穿的比我還像新娘。我一直安慰自己毅人,他們只是感情好吭狡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丈莺,像睡著了一般划煮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缔俄,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天弛秋,我揣著相機(jī)與錄音蟹略,去河邊找鬼。 笑死挖炬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的状婶。 我是一名探鬼主播意敛,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼膛虫!你這毒婦竟也來了空闲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤走敌,失蹤者是張志新(化名)和其女友劉穎碴倾,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡跌榔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年异雁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片僧须。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖担平,靈堂內(nèi)的尸體忽然破棺而出暂论,到底是詐尸還是另有隱情面褐,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布展哭,位于F島的核電站,受9級(jí)特大地震影響闻蛀,放射性物質(zhì)發(fā)生泄漏匪傍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一觉痛、第九天 我趴在偏房一處隱蔽的房頂上張望役衡。 院中可真熱鬧,春花似錦映挂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芳肌,卻和暖如春翎迁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痴腌。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工柿菩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留懦胞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓凉泄,卻偏偏與公主長得像躏尉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子后众,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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

  • 重點(diǎn)參考鏈接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi閱讀 4,453評(píng)論 0 15
  • 一篇搞定事件傳遞胀糜、響應(yīng)者鏈條、hitTest和pointInside的使用發(fā)生觸摸事件后蒂誉,系統(tǒng)會(huì)將該事件加入到一個(gè)...
    克魯?shù)吕?/span>閱讀 1,120評(píng)論 0 1
  • 前言: 按照時(shí)間順序教藻,事件的生命周期是這樣的: 事件的產(chǎn)生和傳遞(事件如何從父控件傳遞到子控件并尋找到最合適的vi...
    reviewThis閱讀 729評(píng)論 1 2
  • 一陰一陽之謂道。在工作生活中要遵循相關(guān)的規(guī)則右锨,在閑下來靜下來要觀照內(nèi)心的感受括堤。此謂一陰一陽也。 在工作生活中要刻意...
    一日一課閱讀 286評(píng)論 0 1
  • “姑娘绍移,且隨我來悄窃。”雪梅踏進(jìn)宮門蹂窖,見一個(gè)被周圍人稱作王公公的人向她走來轧抗。“你初來乍到瞬测,宮中的規(guī)矩知道的少横媚,隨別人做...
    離情難似竹無心閱讀 390評(píng)論 6 6