iOS 簡單的自定義凸起(不規則)tabbar
阿新 • • 發佈:2019-01-08
主要實現思路:
1.重寫UITabBar:在init裡面建立一個button來實現不規則的圖示(新增新按鈕)放在最中間 -(void)layoutSubviews
調整系統原本的圖示的座標(為中間這個控制元件留出位置)
2.重寫-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
避免按鈕超區不可點選
看具體的程式碼:
自定義SamTabBar檢視
//
// SamTabBar.h
// MoJing
//
// Created by linpeng on 2017/3/15.
// Copyright © 2017年 linpeng. All rights reserved.
//
#import <UIKit/UIKit.h>
//tab頁面個數
typedef NS_ENUM(NSInteger, SamItemUIType) {
SamItemUIType_Three = 3,//底部3個選項
SamItemUIType_Five = 5,//底部5個選項
};
@class SamTabBar;
@protocol SamTabBarDelegate <NSObject>
-(void)tabBar:(SamTabBar *)tabBar clickCenterButton:(UIButton *)sender;
@end
@interface SamTabBar : UITabBar
@property (nonatomic, weak) id<SamTabBarDelegate> tabDelegate;
@property (nonatomic, strong) NSString *centerBtnTitle;
@property (nonatomic, strong) NSString *centerBtnIcon;
+(instancetype)instanceCustomTabBarWithType:(SamItemUIType)type;
@end
m檔案
//
// SamTabBar.m
// MoJing
//
// Created by linpeng on 2017/3/15.
// Copyright © 2017年 linpeng. All rights reserved.
//
#import "SamTabBar.h"
@interface SamTabBar()
@property(nonatomic, strong) UIButton *centerButton;
@property(nonatomic, strong) UILabel *centerTitle;
@property (nonatomic,assign) SamItemUIType type;
@end
@implementation SamTabBar
+(instancetype)instanceCustomTabBarWithType:(SamItemUIType)type{
SamTabBar *tabBar = [[SamTabBar alloc] init];
tabBar.type = type;
return tabBar;
}
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.translucent = NO;
UIButton *plusBtn = [UIButton buttonWithType:UIButtonTypeCustom];
self.centerButton = plusBtn;
[plusBtn addTarget:self action:@selector(plusBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:plusBtn];
UILabel *lblTitle = [[UILabel alloc] init];
self.centerTitle = lblTitle;
lblTitle.font = [UIFont systemFontOfSize:10];
lblTitle.textColor = [UIColor blackColor];
lblTitle.textAlignment = NSTextAlignmentCenter;
[self addSubview:lblTitle];
}
return self;
}
-(void)plusBtnDidClick{
if (self.tabDelegate && [self.tabDelegate respondsToSelector:@selector(tabBar:clickCenterButton:)]) {
[self.tabDelegate tabBar:self clickCenterButton:self.centerButton];
}
}
// 調整子檢視的佈局
-(void)layoutSubviews{
[super layoutSubviews];
CGFloat width = self.frame.size.width/self.type;
Class class = NSClassFromString(@"UITabBarButton");
for (UIView *view in self.subviews) {
if ([view isEqual:self.centerTitle]) {//self.centerButton
view.frame = CGRectMake(0, 0, width, 15);
view.center = CGPointMake(self.frame.size.width/2, self.frame.size.height - view.frame.size.height + 8);
}else if ([view isEqual:self.centerButton]) {//self.centerButton
view.frame = CGRectMake(0, 0, width, self.frame.size.height);
[view sizeToFit];
view.center = CGPointMake(self.frame.size.width/2, 10);
}else if ([view isKindOfClass:class]){//system button
CGRect frame = view.frame;
int indexFromOrign = view.frame.origin.x/width;//防止UIView *view in self.subviews 獲取到的不是有序的
if (indexFromOrign >= (self.type - 1) / 2) {
indexFromOrign++;
}
CGFloat x = indexFromOrign * width;
//如果是系統的UITabBarButton,那麼就調整子控制元件位置,空出中間位置
view.frame = CGRectMake(x, view.frame.origin.y, width, frame.size.height);
//調整badge postion
for (UIView *badgeView in view.subviews){
NSString *className = NSStringFromClass([badgeView class]);
// Looking for _UIBadgeView
if ([className rangeOfString:@"BadgeView"].location != NSNotFound){
badgeView.layer.transform = CATransform3DIdentity;
badgeView.layer.transform = CATransform3DMakeTranslation(-17.0, 1.0, 1.0);
break;
}
}
}
}
}
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
//這一個判斷是關鍵,不判斷的話push到其他頁面,點擊發布按鈕的位置也是會有反應的,這樣就不好了
//self.isHidden == NO 說明當前頁面是有tabbar的,那麼肯定是在導航控制器的根控制器頁面
//在導航控制器根控制器頁面,那麼我們就需要判斷手指點選的位置是否在釋出按鈕身上
//是的話讓釋出按鈕自己處理點選事件,不是的話讓系統去處理點選事件就可以了
if (self.isHidden == NO) {
//將當前tabbar的觸控點轉換座標系,轉換到釋出按鈕的身上,生成一個新的點
CGPoint newP = [self convertPoint:point toView:self.centerButton];
//判斷如果這個新的點是在釋出按鈕身上,那麼處理點選事件最合適的view就是釋出按鈕
if ( [self.centerButton pointInside:newP withEvent:event]) {
return self.centerButton;
}else{//如果點不在釋出按鈕身上,直接讓系統處理就可以了
return [super hitTest:point withEvent:event];
}
}
else {//tabbar隱藏了,那麼說明已經push到其他的頁面了,這個時候還是讓系統去判斷最合適的view處理就好了
return [super hitTest:point withEvent:event];
}
}
-(void)setCenterBtnIcon:(NSString *)centerBtnIcon{
_centerBtnIcon = centerBtnIcon;
[self.centerButton setBackgroundImage:[UIImage imageNamed:self.centerBtnIcon] forState:UIControlStateNormal];
[self.centerButton setBackgroundImage:[UIImage imageNamed:self.centerBtnIcon] forState:UIControlStateHighlighted];
}
-(void)setCenterBtnTitle:(NSString *)centerBtnTitle{
_centerBtnTitle = centerBtnTitle;
self.centerTitle.text = centerBtnTitle;
}
@end
用法:
以上自定義的tabbar控制元件就弄好了 現在就可以在VC中使用了
建立一個WBTabBarController 繼承UITabBarController 在appdelegate中
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [[WBTabBarController alloc] init];
kvo的形式新增自定義的tabbar
//kvo形式新增自定義的 UITabBar
SamTabBar *tab = [SamTabBar instanceCustomTabBarWithType:SamItemUIType_Five];
[self setValue:tab forKey:@"tabBar"];
具體的程式碼:
@interface WBTabBarController ()<SamTabBarDelegate>
@end
@implementation WBTabBarController
- (void)awakeFromNib {
[super awakeFromNib];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
}
-(void)setupUI{
[self setupVC];
[[UITabBar appearance] setShadowImage:[UIImage new]];
//kvo形式新增自定義的 UITabBar
SamTabBar *tab = [SamTabBar instanceCustomTabBarWithType:SamItemUIType_Five];
tab.centerBtnTitle = @"釋出";
tab.centerBtnIcon = @"攝影機圖示_點選後";
tab.tabDelegate = self;
[self setValue:tab forKey:@"tabBar"];
}
- (void)setupVC{
[self addChildVc:[[LoginViewController alloc] init] title:@"首頁" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
[self addChildVc:[[LoginViewController alloc] init] title:@"發現" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
[self addChildVc:[[LoginViewController alloc] init] title:@"訊息" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
[self addChildVc:[[LoginViewController alloc] init] title:@"個人中心" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
}
- (void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage{
// 設定子控制器的文字(可以設定tabBar和navigationBar的文字)
childVc.title = title;
// 設定子控制器的tabBarItem圖片
childVc.tabBarItem.image = [UIImage imageNamed:image];
// 禁用圖片渲染
childVc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImage] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
// 設定文字的樣式
[childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal];
[childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor redColor]} forState:UIControlStateSelected];
// 為子控制器包裝導航控制器
WBBaseNC *navigationVc = [[WBBaseNC alloc] initWithRootViewController:childVc];
// 新增子控制器
[self addChildViewController:navigationVc];
}
-(void)tabBar:(SamTabBar *)tabBar clickCenterButton:(UIButton *)sender{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"點選了中間按鈕" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
[alert addAction:action];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
效果如圖:
gif效果如圖:
修改tabbar上那條很醜的分割線:
-(void)setupUI{
[self setupVC];
//kvo形式新增自定義的 UITabBar
SamTabBar *tab = [SamTabBar instanceCustomTabBarWithType:SamItemUIType_Five];
tab.centerBtnTitle = nil;
tab.centerBtnIcon = @"menu_diary_pr";
tab.tabDelegate = self;
[self setValue:tab forKey:@"tabBar"];
//去除頂部很醜的border
[[UITabBar appearance] setShadowImage:[UIImage new]];
[[UITabBar appearance] setBackgroundImage:[[UIImage alloc]init]];
//自定義分割線顏色
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(self.tabBar.bounds.origin.x-0.5, self.tabBar.bounds.origin.y, self.tabBar.bounds.size.width+1, self.tabBar.bounds.size.height+2)];
bgView.layer.borderColor = COLOR_SEPERATOR.CGColor;
bgView.layer.borderWidth = 0.5;
[tab insertSubview:bgView atIndex:0];
tab.opaque = YES;
}
效果: