- 先看下效果
- 為什么還要繼續(xù)說這個(gè)內(nèi)容呢阀捅?
- 前一段微博上很火的tabbar封裝大賽想必大家都知道吧,各位大神盡其所能
- 自己正在仿寫閑魚锋爪,看了網(wǎng)上一些朋友寫的關(guān)于tabbar中間按鈕的處理水泉,發(fā)現(xiàn)關(guān)于處理中間按鈕的點(diǎn)擊這塊有點(diǎn)模糊
- 個(gè)人估計(jì)是大家在寫這一塊的時(shí)候忽略了這個(gè)細(xì)節(jié)
- 有的是中間按鈕凸起的部分點(diǎn)擊沒有反應(yīng),按鈕其他地方可以點(diǎn)擊
- 有的是中間凸起按鈕可以完全點(diǎn)擊了掏婶,但是沒有做細(xì)節(jié)處理啃奴,導(dǎo)致push到其他頁(yè)面,在和凸起按鈕同樣的位置還可以被點(diǎn)擊雄妥,而且點(diǎn)擊效果和點(diǎn)擊凸起按鈕效果是一樣的
- 還有的是雖然實(shí)現(xiàn)了功能最蕾,但是處理方法上并不是很完善
因此決定熬夜寫下這篇文章,幫助有需要的朋友看一下
突然感覺沒有什么可說的了老厌,哈哈揖膜,主要是我代碼里面已經(jīng)寫得非常詳細(xì)了,而且文字多了效果也不好
簡(jiǎn)單的說下大致結(jié)構(gòu)和思路吧
tabbar的話也是遵循主流梅桩,自定義一個(gè)繼承自系統(tǒng)UITabbar的LBTabbar壹粟,然后用KVC和系統(tǒng)的進(jìn)行替換
中間的凸起按鈕和tabbar內(nèi)部的子控件不是同一類型,是一個(gè)UIButton而已
根據(jù)tabbar內(nèi)部子控件的類型去調(diào)整內(nèi)部子控件的位置宿百,從而騰出一個(gè)中間位置給凸起按鈕
給tabbar弄一個(gè)代理趁仙,添加一個(gè)點(diǎn)擊中間凸起按鈕的代理方法,讓LBTabBarController成為它的代理垦页,實(shí)現(xiàn)對(duì)應(yīng)代理方法即可實(shí)現(xiàn)按鈕點(diǎn)擊
如果對(duì)以上步驟有不清楚的地方可以看代碼或者隨時(shí)咨詢我哦雀费,這篇文字主要講的核心就是中間按鈕點(diǎn)擊
1)要想監(jiān)聽整個(gè)發(fā)布按鈕的點(diǎn)擊,包括凸起部分點(diǎn)擊也有反應(yīng)痊焊,那么我是通過在自定義的LBTabbar內(nèi)部重寫- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)even
方法來實(shí)現(xiàn)的
2)我們都知道盏袄,凸起按鈕是自定義的LBTabbar的子控件,默認(rèn)情況下子控件尺寸如果超出父控件薄啥,那么超出的部分點(diǎn)擊是沒有反應(yīng)的
3)hitTest
這個(gè)方法就是專門返回一個(gè)處理響應(yīng)事件最合適view的辕羽,一般情況下我們不實(shí)現(xiàn)這個(gè)方法,默認(rèn)就是讓系統(tǒng)幫我們?nèi)ヅ袛嗵幚硎录憫?yīng)最合適的view垄惧,一旦我們想要改變一下這種情況刁愿,我們就需要通過重寫這個(gè)方法
4)我們的需求是只要我們點(diǎn)擊的point在凸起按鈕的任何位置(無論是否超出tabbar)都可以有響應(yīng),那么我們首先需要判斷這個(gè)point是否在凸起按鈕自身上
[self convertPoint:point toView:self.plusBtn]
這句代碼就是將當(dāng)前tabbar的觸摸點(diǎn)轉(zhuǎn)換坐標(biāo)系到逊,轉(zhuǎn)換到凸起按鈕的身上铣口,它會(huì)生成一個(gè)新的點(diǎn),然后我們通過
[self.plusBtn pointInside:newP withEvent:event]
方法判斷如果這個(gè)新的點(diǎn)是在發(fā)布按鈕身上觉壶,那么處理點(diǎn)擊事件最合適的view就是發(fā)布按鈕脑题,否則直接讓系統(tǒng)幫我們處理點(diǎn)擊事件就可以了
5)對(duì)了,這里還有一步也是非常關(guān)鍵铜靶,因?yàn)槲覀冎貙懥藢ふ易詈线mview的方法叔遂,那么我們還需要考慮什么情況下我們需要由我們自己選擇最合適的view,什么情況下不需要,所以我們需要加一個(gè)判斷if (self.isHidden == NO)
掏熬,
這句代碼代表了當(dāng)前頁(yè)面是有tabbar的,那么肯定是在導(dǎo)航控制器的根控制器頁(yè)面秒梅,這個(gè)時(shí)候就需要由我們自己選擇最合適的view旗芬,其他的push頁(yè)面直接讓系統(tǒng)選擇
6)如果不做第五步判斷,bug就是由導(dǎo)航控制器的根控制器頁(yè)面push到其他頁(yè)面后捆蜀,點(diǎn)擊該頁(yè)面和tabbar凸起按鈕同樣的位置也會(huì)有反應(yīng)
7)好了疮丛,該上關(guān)鍵代碼了
//重寫hitTest方法,去監(jiān)聽發(fā)布按鈕的點(diǎn)擊辆它,目的是為了讓凸出的部分點(diǎn)擊也有反應(yīng)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//這一個(gè)判斷是關(guān)鍵誊薄,不判斷的話push到其他頁(yè)面,點(diǎn)擊發(fā)布按鈕的位置也是會(huì)有反應(yīng)的锰茉,這樣就不好了
//self.isHidden == NO 說明當(dāng)前頁(yè)面是有tabbar的呢蔫,那么肯定是在導(dǎo)航控制器的根控制器頁(yè)面
//在導(dǎo)航控制器根控制器頁(yè)面,那么我們就需要判斷手指點(diǎn)擊的位置是否在發(fā)布按鈕身上
//是的話讓發(fā)布按鈕自己處理點(diǎn)擊事件飒筑,不是的話讓系統(tǒng)去處理點(diǎn)擊事件就可以了
if (self.isHidden == NO) {
//將當(dāng)前tabbar的觸摸點(diǎn)轉(zhuǎn)換坐標(biāo)系片吊,轉(zhuǎn)換到發(fā)布按鈕的身上,生成一個(gè)新的點(diǎn)
CGPoint newP = [self convertPoint:point toView:self.plusBtn];
//判斷如果這個(gè)新的點(diǎn)是在發(fā)布按鈕身上协屡,那么處理點(diǎn)擊事件最合適的view就是發(fā)布按鈕
if ( [self.plusBtn pointInside:newP withEvent:event]) {
return self.plusBtn;
}else{//如果點(diǎn)不在發(fā)布按鈕身上俏脊,直接讓系統(tǒng)處理就可以了
return [super hitTest:point withEvent:event];
}
}
else {//tabbar隱藏了,那么說明已經(jīng)push到其他的頁(yè)面了肤晓,這個(gè)時(shí)候還是讓系統(tǒng)去判斷最合適的view處理就好了
return [super hitTest:point withEvent:event];
}
}
下面是排布tabbar里面的子控件的
- (void)layoutSubviews
{
[super layoutSubviews];
//系統(tǒng)自帶的按鈕類型是UITabBarButton爷贫,找出這些類型的按鈕,然后重新排布位置补憾,空出中間的位置
Class class = NSClassFromString(@"UITabBarButton");
self.plusBtn.size = CGSizeMake(self.plusBtn.currentBackgroundImage.size.width, self.plusBtn.currentBackgroundImage.size.height);
self.plusBtn.centerX = self.centerX;
//調(diào)整發(fā)布按鈕的中線點(diǎn)Y值
self.plusBtn.centerY = self.height * 0.5 - 2*LBMagin ;
UILabel *label = [[UILabel alloc] init];
label.text = @"發(fā)布";
label.font = [UIFont systemFontOfSize:11];
[label sizeToFit];
label.textColor = [UIColor grayColor];
[self addSubview:label];
label.centerX = self.plusBtn.centerX;
label.centerY = CGRectGetMaxY(self.plusBtn.frame) + LBMagin ;
int btnIndex = 0;
for (UIView *btn in self.subviews) {//遍歷tabbar的子控件
if ([btn isKindOfClass:class]) {//如果是系統(tǒng)的UITabBarButton漫萄,那么就調(diào)整子控件位置,空出中間位置
//每一個(gè)按鈕的寬度==tabbar的五分之一
btn.width = self.width / 5;
btn.x = btn.width * btnIndex;
btnIndex++;
//如果是索引是2(從0開始的)盈匾,直接讓索引++卷胯,目的就是讓消息按鈕的位置向右移動(dòng),空出來發(fā)布按鈕的位置
if (btnIndex == 2) {
btnIndex++;
}
}
}
}
- OK威酒,結(jié)束了窑睁,不足之處歡迎大家指正,共同學(xué)習(xí)
代碼地址