1. 程式人生 > >ios自定義中間凸出 UITabBar,so easy……

ios自定義中間凸出 UITabBar,so easy……

IOS 自定義UITabBar ,中間按鈕凸出

很多專案中都有中間凸出的UI設計,這個不規則的設計才坑爹,必須要自定義。在安卓上 做這個也是坑,現在只說ios的實現。


示意圖: 
demo示意圖

問題和難點:

  1. 橫線,凸出部分上的黑色半圓線;
  2. 超出UITabbr部分的點選事件;
  3. UITabBar 隱藏後,上面自定義的凸出按鈕隱藏。
  4. 按鈕點選事件傳遞。

方案:

  1. 自定義UITabBar;
  2. 重寫UITabBar的layoutSubviews,重新排列底部的UITabBarButton,並在中間加入自定義的按鈕,新增點選監聽,處理點選事件。
  3. 自定義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隱藏的時候,擷取的,可以看出被移動到螢幕最下方。

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{


}