ios自定義中間凸出 UITabBar,so easy……
阿新 • • 發佈:2019-01-02
IOS 自定義UITabBar ,中間按鈕凸出
很多專案中都有中間凸出的UI設計,這個不規則的設計才坑爹,必須要自定義。在安卓上 做這個也是坑,現在只說ios的實現。
示意圖:
問題和難點:
- 橫線,凸出部分上的黑色半圓線;
- 超出UITabbr部分的點選事件;
- UITabBar 隱藏後,上面自定義的凸出按鈕隱藏。
- 按鈕點選事件傳遞。
方案:
- 自定義UITabBar;
- 重寫UITabBar的layoutSubviews,重新排列底部的UITabBarButton,並在中間加入自定義的按鈕,新增點選監聽,處理點選事件。
- 自定義UITabBarController ,通過kvc 替換自己的UITabBar;
解決:
我的解決方法:
1、中間的是一個圓形圖片按鈕,下面是一個UIlabel,組成了中間的按鈕。
2、在自定義的UITab 上自己畫一條橫線,流出中間部分不畫。
3、在中間加入一個自定義的UIView,在UIView中畫半圓,設定UIView 的masksToBounds為YES;設定layer的cornerRadius 為他的寬高的一半,這樣他就是一個白色的半圓,並有一個黑色半圓。
1.自定義半圓UIView
//H 檔案:
#define SINGLE_LINE_WIDTH (1 / [UIScreen mainScreen].scale)
#define SINGLE_LINE_ADJUST_OFFSET ((1 / [UIScreen mainScreen].scale) / 2)
@interface GBArcView : UIView
@end
//M 檔案:
#import "GBArcView.h"
#import "UIView+Extension.h"// 用了其他程式碼,這個大家自己找一下
@implementation GBArcView
//繪製半圓
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, RGB_COLOR(200, 200 , 200).CGColor);
CGContextSetLineWidth(context, SINGLE_LINE_WIDTH);
CGContextBeginPath(context);
CGFloat lineMargin =self.width*0.5f;
//1px線,偏移畫素點
CGFloat pixelAdjustOffset = 0;
if (((int)(1 * [UIScreen mainScreen].scale) + 1) % 2 == 0) {
pixelAdjustOffset = SINGLE_LINE_ADJUST_OFFSET;
}
CGFloat yPos = self.width*0.5f - pixelAdjustOffset;
CGFloat xPos = self.width*0.5f - pixelAdjustOffset;
CGContextAddArc(context, xPos, yPos, self.width*0.5f, M_PI, 0, 0);
CGContextStrokePath(context);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
2、自定義UITabbar
//H 檔案
#import <UIKit/UIKit.h>
@class GBTabBar;
//自定義按鈕點選事件代理
@protocol GBTabBarViewDelegate <NSObject>
- (void) mainTabBarViewDidClick : (GBTabBar *)hBTabBarView;
@end
@interface GBTabBar : UITabBar
@property(nonatomic,weak) id<GBTabBarViewDelegate> tabbarDelegate;
@end
//M 檔案
#import "GBTabBar.h"
#import <UIKit/UIKit.h>
#import "UIView+Extension.h"
#import "GBArcView.h"
@interface GBTabBar()
@property (nonatomic,strong) UIButton *addButton;//自定義圓形圖片按鈕
@property (nonatomic,strong) UILabel *titleLabel;//中間自定義文字
@property (nonatomic,strong) GBArcView *view; //半圓View
@property(assign,nonatomic)int index;//UITabBar子view的索引
@end
@implementation GBTabBar
//繪製橫線
- (void)drawRect:(CGRect)rect {
//中間的按鈕寬度是UItabBar的高度,其他按鈕的寬度就是,(self.width-self.height)/4.0
CGFloat buttonW = (self.width-self.height)/4.0;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, RGB_COLOR(200, 200, 200).CGColor);
CGContextSetLineWidth(context, SINGLE_LINE_WIDTH);
CGContextBeginPath(context);
CGFloat lineMargin =0;
//1PX線,畫素偏移
CGFloat pixelAdjustOffset = 0;
if (((int)(1 * [UIScreen mainScreen].scale) + 1) % 2 == 0) {
pixelAdjustOffset = SINGLE_LINE_ADJUST_OFFSET;
}
CGFloat yPos = lineMargin - pixelAdjustOffset;
//第一段線
CGContextMoveToPoint(context, 0, yPos);
CGContextAddLineToPoint(context, buttonW*2+SINGLE_LINE_WIDTH*2, yPos);
CGContextStrokePath(context);
//第二段線
CGContextMoveToPoint(context, buttonW*2+self.height-SINGLE_LINE_WIDTH*2, yPos);
CGContextAddLineToPoint(context, self.bounds.size.width, yPos);
CGContextSetStrokeColorWithColor(context, RGB_COLOR(200, 200, 200).CGColor);
CGContextStrokePath(context);
}
//自定義的按鈕點選事件處理,如果點選的點在自定義的按鈕中,就返回自定義按鈕處理事件。如果不處理,那麼按鈕只有在UITabrBar 中的 一半可以被點選,有點選事件響應。
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
//判斷點是否在按鈕上,如果是就讓按鈕處理事件
if(CGRectContainsPoint(self.addButton.frame, point)){
return self.addButton ;
}
return [super hitTest:point withEvent:event];
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
//重新初始化方法,從stroyboard 中載入,會呼叫
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
self.backgroundColor=[UIColor whiteColor];
self.clipsToBounds=NO;//不裁剪子控制元件
self.index=0;//初始化索引
//設定tabBaritem 的文字顏色
[[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:RGB_COLOR(74, 74, 74), UITextAttributeTextColor, nil] forState:UIControlStateNormal];
[[UITabBarItem appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:RGB_COLOR(0, 147, 197),UITextAttributeTextColor, nil]forState:UIControlStateSelected];
}
return self;
}
//自定義按鈕的懶載入
-(UIButton *)addButton{
if(!_addButton){
UIButton *button=[[UIButton alloc] init];
self.addButton = button;
[self.addButton setImage:[UIImage imageNamed:@"tab_open"] forState:UIControlStateNormal];
[self.addButton addTarget:self action:@selector(addClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.addButton];
}
return _addButton;
}
//自定義半圓View的懶載入
-(UIView *)view{
if(!_view){
CGFloat buttonW = (self.width-self.height)/4.0;
GBArcView *view = [[GBArcView alloc]initWithFrame:CGRectMake(buttonW*2, -self.height*0.5f, self.height, self.height)];
view.backgroundColor=[UIColor whiteColor];
view.layer.masksToBounds=YES;
view.layer.cornerRadius=self.height*0.5f;
_view=view;
[self addSubview:view];
}
return _view;
}
-(UILabel *)titleLabel{
if(!_titleLabel){
UILabel *titleLabel=[[UILabel alloc] init];
titleLabel.text[email protected]"開門";
titleLabel.textColor=[UIColor blackColor];
titleLabel.font=[UIFont systemFontOfSize:12.0];
[titleLabel sizeToFit];
_titleLabel = titleLabel;
[self addSubview:titleLabel];
}
return _titleLabel;
}
//重寫layoutSubviews,重新排布子View
-(void)layoutSubviews{
self.index=0;
[super layoutSubviews];
CGFloat buttonW = SCREEN_WIDTH * 0.2 ;//SCREEN_WIDTH * 0.2
for (int i = 0; i < self.subviews.count; i ++) {
UIView *view = self.subviews[i];
if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
CGRect rect=view.frame;
rect.size.width=buttonW;
rect.size.height=self.frame.size.height;
rect.origin.y=0;
view.frame =rect;
if(self.index<2){
view.x=self.index*buttonW;
}else if(self.index>=2){
view.x=self.index*buttonW +buttonW;
}
self.index++;
}
}
//懶載入 等所有控制元件排布後,然後 設定自定義的view,這裡注意順序,先設定背景的半圓view的Frame,然後設定按鈕的Frame,否則半圓view會擋住按鈕。
self.view.x=2 * (self.width-self.height)/4.0;
self.addButton.width = self.height;
self.addButton.height = self.height;
self.addButton.y = -self.height*0.5f;
self.addButton.x = 2 * (self.width-self.height)/4.0;
self.titleLabel.center=CGPointMake(self.width*0.5f, CGRectGetMaxY(self.addButton.frame)+self.titleLabel.bounds.size.height*0.5f);
}
-(void)setHidden:(BOOL)hidden{
[super setHidden:hidden];
//手動設定UITabBar 隱藏時,我們要將自定義的按鈕和背景隱藏
[self.view setHidden:hidden];
[self.addButton setHidden:hidden];
}
//******核心部分******
//當配置 hidesBottomBarWhenPushed 的viewController ,隱藏UITabBar時,會改變其frame,就是將UITabBar 的Y值設為螢幕最大的y值,就不可見。我們重寫這個方法,判斷當frame的y小於螢幕的高度 ,那麼UITabBar就是被隱藏了,這時候我們將自定的控制元件隱藏。相反的,我們就顯示我們的自定義控制元件。
-(void)setFrame:(CGRect)frame{
[super setFrame:frame];
if(frame.origin.y>=[UIScreen mainScreen].bounds.size.height){
[self.view setHidden:YES];
[self.addButton setHidden:YES];
}else{
[self.view setHidden:NO];
[self.addButton setHidden:NO];
}
}
- (void)addClick
{
//代理點選事件
if ([self.tabbarDelegate respondsToSelector:@selector(mainTabBarViewDidClick:)]) {
[self.tabbarDelegate mainTabBarViewDidClick:self];
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
補一個圖,這個是UITabbar隱藏的時候,擷取的,可以看出被移動到螢幕最下方。
3、自定義UITabBarController
這裡比較簡單了,就是替換系統的UItabbr 為自己的UItabbar;
由於我的專案是stroyboard 寫的,替換比較簡單。
@interface HomeTabBarController ()<GBTabBarViewDelegate>
@property (nonatomic, strong) NSArray *items;
@end
@implementation HomeTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
//tabBar是UITabBarController的只讀成員變數(屬性),是不讓修改的
//kvc 替換系統的tabbar
// GBTabBar *tabBar = [[GBTabBar alloc] init];
// [self setValue:tabBar forKeyPath:@"tabBar"];
//已經替換的UItabbar 設定代理為當前控制器
[self.tabBar setValue:self forKey:@"tabbarDelegate"];
}
//代理方法 ,自定義按鈕點選
-(void)mainTabBarViewDidClick:(GBTabBar *)hBTabBarView{
}