iOS開發(fā)小記:運(yùn)用Runtime機(jī)制擴(kuò)大UIButton的響應(yīng)區(qū)域

轉(zhuǎn)載自 iOS開發(fā)小記:運(yùn)用Runtime機(jī)制擴(kuò)大UIButton的響應(yīng)區(qū)域

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。? ? ? Hello大家好,我是李永樂(lè)。? ? ? 在iOS開發(fā)中,有時(shí)會(huì)將一個(gè)UIButton的外觀設(shè)置成很小,從而使其點(diǎn)按操作變得很不容易,因?yàn)辄c(diǎn)按的區(qū)域是根據(jù)UIButton的frame決定的。解決這個(gè)問(wèn)題的辦法一般是把button的frame放大,然后把里面的內(nèi)容縮小,但是這樣做總是感覺(jué)不倫不類,還需要分別重新調(diào)整Button的frame和顯示內(nèi)容的frame,比較麻煩。今天筆者在外國(guó)網(wǎng)站總結(jié)了一種方法,通過(guò)OC創(chuàng)建類別的方式,運(yùn)用Runtime關(guān)聯(lián)對(duì)象的方法,對(duì)UIButton進(jìn)行了擴(kuò)展 ,創(chuàng)建一個(gè)方法直接用于擴(kuò)大Button的點(diǎn)按區(qū)域,而不改變它的顯示內(nèi)容,使代碼的可讀性大大增強(qiáng)。? ? ? 其執(zhí)行原理為:OC中創(chuàng)建類別(Categroy)的方式,并不允許給已有的類擴(kuò)展屬性,只可以給其擴(kuò)展方法。所以,需要使用Runtime“黑魔法”中的關(guān)聯(lián)對(duì)象(Associative Object)的一些方法,動(dòng)態(tài)地為某個(gè)button對(duì)象添加擴(kuò)展距離的屬性,然后檢測(cè)UITouch事件的觸摸點(diǎn)是否在我們擴(kuò)展距離后Rect內(nèi),從而達(dá)到想要的效果。? ? ? 首先,創(chuàng)建一個(gè)UIButton的Category,起名為EnlargeTouchArea,設(shè)置一個(gè)外界可訪問(wèn)的方法setEnlaEdgeWithTop:right:bottom:left,在使用時(shí)也只需使用這個(gè)方法即可,傳入的四個(gè)參數(shù)分別是上、右、下、左的擴(kuò)展距離。[objc] view plain copy//? UIButton+EnlargeTouchArea.h? ? #import#import@interface UIButton (EnlargeTouchArea)? ? - (void)setEnlargeEdgeWithTop:(CGFloat) top right:(CGFloat) right bottom:(CGFloat) bottom left:(CGFloat) left;? ? @end? ? ? ? ? 然后導(dǎo)入,所有Runtime的黑魔法都在這里[objc] view plain copy//? UIButton+EnlargeTouchArea.m? ? #import "UIButton+EnlargeTouchArea.h"? ? #import@implementation UIButton (EnlargeTouchArea)

static char topNameKey;

static char rightNameKey;

static char bottomNameKey;

static char leftNameKey;

objc_setAssociatedObject是一個(gè)C語(yǔ)言函數(shù),這個(gè)函數(shù)被稱之為“關(guān)聯(lián)API”,它的作用是把top、right、bottom、left這四個(gè)從外界獲取到的值與本類(self)關(guān)聯(lián)起來(lái),然后設(shè)置一個(gè)static char作為能夠找到他們的Key

[objc] view plain copy

- (void) setEnlargeEdgeWithTop:(CGFloat) top right:(CGFloat) right bottom:(CGFloat) bottom left:(CGFloat) left

{

objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);

objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);

objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC);

objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);

}

objc_getAssociatedObject同樣也是一個(gè)關(guān)聯(lián)API(c語(yǔ)言函數(shù)),它可以通過(guò)剛剛設(shè)置的Key找到上個(gè)方法中從外界傳入的top、right、bottom、left,這個(gè)api和obj_setAssociatedObject一起使用就可以達(dá)到給已有類擴(kuò)展屬性的效果。最后我們通過(guò)self.bounds設(shè)置一個(gè)新的CGRect,作為擴(kuò)大后的點(diǎn)按區(qū)域,并且返回

[objc] view plain copy

- (CGRect) enlargedRect

{

NSNumber* topEdge = objc_getAssociatedObject(self, &topNameKey);

NSNumber* rightEdge = objc_getAssociatedObject(self, &rightNameKey);

NSNumber* bottomEdge = objc_getAssociatedObject(self, &bottomNameKey);

NSNumber* leftEdge = objc_getAssociatedObject(self, &leftNameKey);

if (topEdge && rightEdge && bottomEdge && leftEdge)

{

return CGRectMake(self.bounds.origin.x - leftEdge.floatValue,

self.bounds.origin.y - topEdge.floatValue,

self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue,

self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue);

}

else

{

return self.bounds;

}

}

這個(gè)方法UIView的一個(gè)實(shí)例方法,作用是,捕獲當(dāng)前的UITouch事件中的觸摸點(diǎn),檢測(cè)它是否在最上層的子視圖內(nèi),如果不是的話就遞歸檢測(cè)其父視圖。這樣的話,我們就只是將當(dāng)前某一個(gè)觸摸的point與某一個(gè)rect進(jìn)行比較,并沒(méi)有改變Button真實(shí)的frame,從而真正的從邏輯上達(dá)到了只是擴(kuò)大點(diǎn)按區(qū)域的效果。

[objc] view plain copy

- (UIView*) hitTest:(CGPoint) point withEvent:(UIEvent*) event

{

CGRect rect = [self enlargedRect];

if (CGRectEqualToRect(rect, self.bounds))

{

return [super hitTest:point withEvent:event];

}

return CGRectContainsPoint(rect, point) ? self : nil;

}

總結(jié)一下,為什么要用runtime去為已有類達(dá)到一個(gè)擴(kuò)展屬性的效果呢,正是因?yàn)樯厦孢@個(gè)方法,這個(gè)系統(tǒng)提供的方法并沒(méi)有提供接受其他參數(shù)的地方,而我們卻必須要指定一個(gè)擴(kuò)大的區(qū)域作為參數(shù),所以就必須為這個(gè)類擴(kuò)展一個(gè)新的屬性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容