身為一個沒有女朋友的屌絲程序猿肌括,幸虧還有蒼老師可以想想点骑,看看。
帶小紅點的tabbar
其實這種情況比較簡單谍夭,因為系統(tǒng)給我們提供了方法
self.navigationController.tabBarItem.badgeValue = @"1";
系統(tǒng)提供的方法下標默認是紅色黑滴,我們也可以修改顏色
self.navigationController.tabBarItem.badgeColor = [UIColor blackColor];
But
一提但是
我們就知道事情還沒有結(jié)束,當我們的需求只是要求有小紅點紧索,不要數(shù)字的時候跷跪,我們系統(tǒng)給的方法就會有一些問題了。
我們設(shè)置badgeValue為空
self.navigationController.tabBarItem.badgeValue = @"";
圓圈太大齐板,感覺好丑啊吵瞻。這個時候就需要我們來自己定制比較漂亮的小紅點了。
我們寫一個UITabbar的分類badge
甘磨,里面寫一些方法來實現(xiàn)我們的功能
分類里面有兩個方法橡羞,一個是隱藏小紅點,一個是顯示小紅點
/**
顯示小紅點
@param index item
*/
- (void)showBadgeOnItemIndex:(int)index;
/**
隱藏小紅點
@param index item
*/
- (void)hidenBadgeOnItemIndex:(int)index;
在.m文件中我們寫實現(xiàn)方法
#import "UITabBar+badge.h"
#define TabbarItemNums 4.0 //tabbar的數(shù)量 如果是5個設(shè)置為5.0
@implementation UITabBar (badge)
/**
顯示小紅點
@param index item
*/
- (void)showBadgeOnItemIndex:(int)index{
[self removeBadgeOnItemIndex:index];
//新建一個小紅點
UIView *badgeView = [[UIView alloc]init];
badgeView.tag = 100 + index;
badgeView.layer.cornerRadius = 5;//badge的直徑是10
badgeView.backgroundColor = [UIColor redColor];
//設(shè)置frame
CGRect tabbarFrame = self.frame;
float percentX = (index +0.6) / TabbarItemNums;
CGFloat x = ceilf(percentX * tabbarFrame.size.width);
CGFloat y = ceilf(0.1 * tabbarFrame.size.height);
badgeView.frame = CGRectMake(x, y, 10, 10);//圓形大小為10
[self addSubview:badgeView];
};
/**
隱藏小紅點
@param index item
*/
- (void)hidenBadgeOnItemIndex:(int)index{
[self removeBadgeOnItemIndex:index];
};
//移除小紅點
- (void)removeBadgeOnItemIndex:(int)index{
//按照tag值移除小紅點
for (UIView *subView in self.subviews) {
if (subView.tag == 100 + index) {
[subView removeFromSuperview];
}
}
}
我們在需要設(shè)置時導入分類頭文件#import "UITabBar+badge.h"
調(diào)用方法
//顯示
[self.tabBarController.tabBar showBadgeOnItemIndex:2];
//隱藏
[self.tabBarController.tabBar hidenBadgeOnItemIndex:2];
效果圖如下
點擊tabbar沒有執(zhí)行系統(tǒng)事件
要想讓tabbar不執(zhí)行系統(tǒng)事件济舆,我們需要了解一下UITabBarControllerDelegate
的代理事件卿泽,我們常用的有一下幾個代理事件
1、視圖將要切換時調(diào)用滋觉,viewController為將要顯示的控制器签夭,如果返回的值為NO,則無法點擊其它分欄了(viewController指代將要顯示的控制器)
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
NSLog(@"被選中的控制器將要顯示的按鈕");
//return NO;不能顯示選中的控制器
return YES;
}
2椎侠、視圖已經(jīng)切換后調(diào)用第租,viewController 是已經(jīng)顯示的控制器
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(@"視圖顯示后調(diào)用");
}
3、將要開始自定義item的順序
- (void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers
{
NSLog(@"將要開始自定義item時調(diào)用");
NSLog(@"%@",viewControllers);
}
4我纪、將要結(jié)束自定義item的順序
- (void)tabBarController:(UITabBarController *)tabBarController willEndCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers changed:(BOOL)changed
{
NSLog(@"將要結(jié)束自定義item時調(diào)用");
NSLog(@"%@",viewControllers);
}
想要了解更多的關(guān)于tabbar的代理慎宾,大家可以參考這篇文章UITabBarDelegate & UITabBarControllerDelegate詳解
這里我們只需要- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
這個代理事件丐吓。使用之前需要TabBarViewController
在設(shè)置代理UITabBarControllerDelegate
,并且遵守代理self.delegate = self;
自定義事件一:彈出菜單按鈕
學習之前需要先了解一個概念CABasicAnimation
。CABasicAnimation
基礎(chǔ)動畫趟据,通過設(shè)定起始點券犁,終點,時間汹碱,動畫會沿著你這設(shè)定點進行移動粘衬。
實例化
使用方法animationWithKeyPath:對 CABasicAnimation進行實例化,并指定Layer的屬性作為關(guān)鍵路徑進行注冊咳促。
//圍繞y軸旋轉(zhuǎn)CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
設(shè)定動畫的屬性和說明屬性說明
關(guān)鍵代碼1
遵守UITabBarControllerDelegate
協(xié)議稚新,設(shè)置代理self.delegate = self;
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if (tabBarController.selectedIndex == 2){
//點擊第二個的時候創(chuàng)建一個view,覆蓋整個視圖
}
}
關(guān)鍵代碼2:動畫的執(zhí)行
其實的核心就是一個扇形等分等缀,然后根據(jù)勾股定理
計算出每一個菜單的frame枷莉。我參考了這篇文章的代碼思路
CGPoint farPoint = CGPointMake(kRZPopupMenuCenterBtnCenterX + kRZPopupMenuItemFarRadius * cosf(angle), kRZPopupMenuCenterBtnCenterY + kRZPopupMenuItemFarRadius * sinf(angle));
- (void)setupMenuItems
{
CGFloat gapAngle = kRZPopupMenuItemWholeAngle / (self.menuItems.count - 1);
for (RZPopupMenuItem *item in self.menuItems) {
CGFloat angle = kRZPopupMenuItemStartAngle + item.tag * gapAngle;
item.startPoint = CGPointMake(kRZPopupMenuCenterBtnCenterX, kRZPopupMenuCenterBtnCenterY);
CGPoint farPoint = CGPointMake(kRZPopupMenuCenterBtnCenterX + kRZPopupMenuItemFarRadius * cosf(angle), kRZPopupMenuCenterBtnCenterY + kRZPopupMenuItemFarRadius * sinf(angle));
item.farPoint = RotateCGPointAroundCenter(farPoint, self.startPoint, kRZPopupMenuItemStartAngle);
item.farPoint = farPoint;
CGPoint nearPoint = CGPointMake(kRZPopupMenuCenterBtnCenterX + kRZPopupMenuItemNearRadius * cosf(angle), kRZPopupMenuCenterBtnCenterY + kRZPopupMenuItemNearRadius * sinf(angle));
item.nearPoint = RotateCGPointAroundCenter(nearPoint, self.startPoint, kRZPopupMenuItemStartAngle);
item.nearPoint = nearPoint;
CGPoint endPoint = CGPointMake(kRZPopupMenuCenterBtnCenterX + kRZPopupMenuItemEndRadius * cosf(angle), kRZPopupMenuCenterBtnCenterY + kRZPopupMenuItemEndRadius * sinf(angle));
item.endPoint = RotateCGPointAroundCenter(endPoint, self.startPoint, kRZPopupMenuItemStartAngle);;
item.endPoint = endPoint;
item.center = self.startPoint;
item.width = kRZPopupMenuCenterBtnWidth;
item.height = kRZPopupMenuCenterBtnWidth;
[self insertSubview:item belowSubview:self.centerBtn];
}
}
我把我參考的作者的代碼放在這里了,需要的朋友可以拿一下
自定義事件二:雙擊刷新
我們在用支付寶的時候娇昙,細心的同學會發(fā)現(xiàn)尺迂,我們在雙擊tabbar的時候可以刷新。其實原理很簡單冒掌,用到的代理事件跟上面的那一個一樣噪裕。
核心思路
監(jiān)聽點擊了哪一個按鈕,當點擊兩下的時候股毫,發(fā)出一個通知刷新膳音。
怎么判斷點擊了兩下
- 可以根據(jù)時間判定,如果要是聯(lián)系點擊某一個tabbar的時間間隔小于0.5S的話铃诬,就判斷為連續(xù)點擊了兩下祭陷。
- 可以設(shè)置一個tag值紀錄tabBarController.selectedIndex,如果兩次的tag值一樣就發(fā)出通知刷新趣席。
時間判定代碼
1兵志、先定義一個全局變量來記錄上次點擊的時間
@property (strong, nonatomic) NSDate *lastDate;
2、 實現(xiàn)代理方法中的事件
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if (tabBarController.selectedIndex == 2){
NSDate *date = [[NSDate alloc] init];
// 處理雙擊事件
if (date.timeIntervalSince1970 - _lastDate.timeIntervalSince1970 < 0.5) {
//發(fā)出通知
}
_lastDate = date;
}
}
3宣肚、 接收通知想罕,實現(xiàn)刷新
tag值判定代碼
1、先定義一個全局變量來記錄上次點擊了哪一個item
@property (strong, nonatomic)NSInteger tag;
2霉涨、 實現(xiàn)代理方法中的事件
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if (tabBarController.selectedIndex == 2){
if(_tag ==tabBarController.selectedIndex ){
//發(fā)出刷新通知
}
}
}
3按价、 接收通知,實現(xiàn)刷新
Tabbar按鈕變大
方案一:自定制一個button
遇到問題
自定制butto的時候會有一道陰影
解決方法:
button.adjustsImageWhenHighlighted=NO;
笙瑟,或者// 取消tabber的背景色 [[UITabBar appearance] setShadowImage:[[UIImage alloc]init]]; [[UITabBar appearance] setBackgroundImage:[[UIImage alloc]init]];
導航推進下一頁的時候那個大圓按鈕不會消失
解決辦法:寫一個基礎(chǔ)類
baseViewController
,判斷self.navigationController.viewControllers.count
楼镐,當數(shù)值大于1的時候,發(fā)出一個通知隱藏大圓按鈕
核心代碼
如果button和UITabBar一樣高呢往枷,我們就包button的center和UITabBar的center對齊鸠蚪。如果button稍微高那么一點呢今阳,我們做同樣的事情,然后設(shè)定center的Y值茅信,以對應高度的差
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[button setBackgroundImage:highlightImage forState:UIControlStateHighlighted];
CGFloat heightDifference = buttonImage.size.height - self.tabBar.frame.size.height;
if (heightDifference < 0)
button.center = self.tabBar.center;
else
{
CGPoint center = self.tabBar.center;
center.y = center.y - heightDifference/2.0;
button.center = center;
}
[self.view addSubview:button];
方案二:采用繪制背景的方法實現(xiàn)TabBar背景
核心代碼
// 畫背景的方法盾舌,返回 Tabbar的背景
- (UIImageView *)drawTabbarBgImageView
{
NSLog(@"tabBarHeight: %f" , tabBarHeight);// 設(shè)備tabBar高度 一般49
CGFloat radius = 30;// 圓半徑
CGFloat allFloat= (pow(radius, 2)-pow((radius-standOutHeight), 2));// standOutHeight 突出高度 12
CGFloat ww = sqrtf(allFloat);
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, -standOutHeight,ScreenW , tabBarHeight +standOutHeight)];// ScreenW設(shè)備的寬
// imageView.backgroundColor = [UIColor redColor];
CGSize size = imageView.frame.size;
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(size.width/2 - ww, standOutHeight)];
NSLog(@"ww: %f", ww);
NSLog(@"ww11: %f", 0.5*((radius-ww)/radius));
CGFloat angleH = 0.5*((radius-standOutHeight)/radius);
NSLog(@"angleH:%f", angleH);
CGFloat startAngle = (1+angleH)*((float)M_PI); // 開始弧度
CGFloat endAngle = (2-angleH)*((float)M_PI);//結(jié)束弧度
// 開始畫弧:CGPointMake:弧的圓心 radius:弧半徑 startAngle:開始弧度 endAngle:介紹弧度 clockwise:YES為順時針蘸鲸,No為逆時針
[path addArcWithCenter:CGPointMake((size.width)/2, radius) radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
// 開始畫弧以外的部分
[path addLineToPoint:CGPointMake(size.width/2+ww, standOutHeight)];
[path addLineToPoint:CGPointMake(size.width, standOutHeight)];
[path addLineToPoint:CGPointMake(size.width,size.height)];
[path addLineToPoint:CGPointMake(0,size.height)];
[path addLineToPoint:CGPointMake(0,standOutHeight)];
[path addLineToPoint:CGPointMake(size.width/2-ww, standOutHeight)];
layer.path = path.CGPath;
layer.fillColor = [UIColor whiteColor].CGColor;// 整個背景的顏色
layer.strokeColor = [UIColor colorWithWhite:0.765 alpha:1.000].CGColor;//邊框線條的顏色
layer.lineWidth = 0.5;//邊框線條的寬
// 在要畫背景的view上 addSublayer:
[imageView.layer addSublayer:layer];
return imageView;
}
+(CGFloat)getTabBarHeight
{
// 獲取tabBarHeight
UITabBarController *tabBarController =[[UITabBarController alloc]init];
return CGRectGetHeight(tabBarController.tabBar.bounds);
}
參考自實現(xiàn)Tabbar的中間按鈕向上突出的兩種方法
方案三:使用KVC修改
1妖谴、寫一個MYTarbar繼承于UITabBar;
2酌摇、在MYTabbar 上加一個按鈕膝舅,設(shè)置按鈕的image、size窑多,中心點在tabbar的中心點仍稀,按鈕點擊事件可用delegate或者block傳遞;
3埂息、在layoutSubviews重新排布MYTarbar上的UITabBarButton的frame(size.width技潘,origin.x);
需要注意點:是超出tabbar部分沒有點擊事件千康,我們需要擴大點擊相應
/**
重寫hitTest方法享幽,去監(jiān)聽中間按鈕的點擊,目的是為了讓凸出的部分點擊也有反應
@param point 點擊point
@param event 事件
@return view
*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//判斷當前手指是否點擊到中間按鈕上拾弃,如果是值桩,則響應按鈕點擊,其他則系統(tǒng)處理
//首先判斷當前View是否被隱藏了豪椿,隱藏了就不需要處理了
if (self.isHidden == NO) {
//將當前tabbar的觸摸點轉(zhuǎn)換坐標系奔坟,轉(zhuǎn)換到中間按鈕的身上,生成一個新的點
CGPoint newP = [self convertPoint:point toView:self.centerBtn];
//判斷如果這個新的點是在中間按鈕身上搭盾,那么處理點擊事件最合適的view就是中間按鈕
if ( [self.centerBtn pointInside:newP withEvent:event]) {
return self.centerBtn;
}
}
return [super hitTest:point withEvent:event];
}
代碼
#import <UIKit/UIKit.h>
typedef void(^MYTabbarClickBlock)();
@interface MYTabbar : UITabBar
- (void)setBtnClickBlock:(MYTabbarClickBlock)block;
@end
#import "MYTabbar.h"
@interface MYTabbar ()
@property (nonatomic, strong) UIButton *centerBtn;
@property (nonatomic, copy ) MYTabbarClickBlock block;
@end
@implementation MYTabbar
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor blueColor];
[self setBackgroundImage:[UIImage new]];
[self setShadowImage:[UIImage new]];
self.centerBtn = [[UIButton alloc]init];
[self.centerBtn setBackgroundImage:[UIImage imageNamed:@"tab_launch"]
forState:UIControlStateNormal];
[self.centerBtn setBackgroundImage:[UIImage imageNamed:@"tab_launch"]
forState:UIControlStateHighlighted];
self.centerBtn.size = self.centerBtn.currentBackgroundImage.size;
[self.centerBtn addTarget:self action:@selector(centerBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.centerBtn];
}
return self;
}
- (void)centerBtnDidClick {
if (self.block) {
self.block();
}
}
- (void)setBtnClickBlock:(ICETabBarClickBlock)block {
self.block = block;
}
- (void)layoutSubviews {
[super layoutSubviews];
//系統(tǒng)自帶的按鈕類型是UITabBarButton咳秉,找出這些類型的按鈕,然后重新排布位置增蹭,空出中間的位置
Class class = NSClassFromString(@"UITabBarButton");
self.centerBtn.centerX = self.centerX;
//調(diào)整中間按鈕的中線點Y值
self.centerBtn.centerY = (self.height - (self.centerBtn.height - self.height)) * 0.5;
NSInteger btnIndex = 0;
for (UIView *btn in self.subviews) {//遍歷tabbar的子控件
if ([btn isKindOfClass:class]) {//如果是系統(tǒng)的UITabBarButton滴某,那么就調(diào)整子控件位置,空出中間位置
//按鈕寬度為TabBar寬度減去中間按鈕寬度的一半
btn.width = (self.width - self.centerBtn.width) * 0.5;
//中間按鈕前的寬度,這里就3個按鈕滋迈,中間按鈕Index為1
if (btnIndex < 1) {
btn.x = btn.width * btnIndex;
} else { //中間按鈕后的寬度
btn.x = btn.width * btnIndex + self.centerBtn.width;
}
btnIndex++;
//如果是索引是0(從0開始的)霎奢,直接讓索引++,目的就是讓消息按鈕的位置向右移動饼灿,空出來中間按鈕的位置
if (btnIndex == 0) {
btnIndex++;
}
}
}
[self bringSubviewToFront:self.centerBtn];
}
/**
重寫hitTest方法幕侠,去監(jiān)聽中間按鈕的點擊,目的是為了讓凸出的部分點擊也有反應
@param point 點擊point
@param event 事件
@return view
*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//判斷當前手指是否點擊到中間按鈕上碍彭,如果是晤硕,則響應按鈕點擊悼潭,其他則系統(tǒng)處理
//首先判斷當前View是否被隱藏了,隱藏了就不需要處理了
if (self.isHidden == NO) {
//將當前tabbar的觸摸點轉(zhuǎn)換坐標系舞箍,轉(zhuǎn)換到中間按鈕的身上舰褪,生成一個新的點
CGPoint newP = [self convertPoint:point toView:self.centerBtn];
//判斷如果這個新的點是在中間按鈕身上,那么處理點擊事件最合適的view就是中間按鈕
if ( [self.centerBtn pointInside:newP withEvent:event]) {
return self.centerBtn;
}
}
return [super hitTest:point withEvent:event];
}
調(diào)用方法
//利用kvc將系統(tǒng)的tabbar替換成ICETabbar
MYTabbar *tabbar = [[MYTabbar alloc]init];
[self setValue:tabbar forKey:@"tabBar"];
[tabbar setBtnClickBlock:^{
NSLog(@"click Center");
}];