UIKit高度定制 - UINavigationBar的繼承與定制

UINavigationBar的繼承與定制

我們?cè)趇OS項(xiàng)目開發(fā)中,有些時(shí)候需要修改標(biāo)準(zhǔn)控件的樣式,我們今天就圍繞一個(gè)具體項(xiàng)目需求,進(jìn)行UINavigationBar的繼承與改造。

UIApperance協(xié)議屬性定制

我們?cè)?code>UINavigationBar.h頭文件中,看到如下修改NavigationBar背景顏色的屬性

@property(nullable, nonatomic,strong) UIColor *barTintColor NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;  // default is nil

注意到UI_APPEARANCE_SELECTOR這個(gè)宏了么,用這個(gè)宏標(biāo)記的屬性,都是可以通過UIApperance協(xié)議進(jìn)行全局設(shè)置的屬性。說的更直白一點(diǎn),就是可以一次性,修改項(xiàng)目中所有的這個(gè)類的默認(rèn)屬性。

例如在iOS6之前,UILabel的默認(rèn)背景顏色不是透明色,而是白色。我們就可以使用如下方法,修改UILabel的默認(rèn)背景色

 [[UILabel appearance] setBackgroundColor:[UIColor clearColor]];

UIApperance協(xié)議就是這么神奇,所有的UIKit控件都遵守了這個(gè)協(xié)議,所有標(biāo)記了UI_APPEARANCE_SELECTOR宏的屬性,都可以使用appearance實(shí)例修改默認(rèn)值,是不是很炫酷。

項(xiàng)目需求

上面一段與本文正題無關(guān),下面我們看一下本文的項(xiàng)目需求

屏幕快照 2016-01-14 10.44.13.png

分析

這個(gè)頁面就是一個(gè)標(biāo)準(zhǔn)的NavigationController + TableViewContoller組合實(shí)現(xiàn)的設(shè)置頁面,導(dǎo)航條和Table的樣式需要訂制。

前面說到的UIApperance協(xié)議是可以實(shí)現(xiàn)的,我們換一種更為普遍的方式實(shí)現(xiàn),繼承

我們繼承UINavigationBar,創(chuàng)建子類FWBar。我們使用storyboard實(shí)例化大體框架模型,并將NavigationViewControllerNavigationBar設(shè)置為我們的FWBar類,并將UITableView設(shè)置為Static靜態(tài)模式,直接編輯了Cell的內(nèi)容。

屏幕快照 2016-01-14 10.51.44.png

FWBar.m中加入如下代碼

- (void)awakeFromNib
{
    [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsCompact];
    self.shadowImage = [UIImage new];
    
    //把之前的View統(tǒng)統(tǒng)隱藏
    [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [obj setHidden:YES];
    }];
    
    
    [self addSubview:self.fakeBackgroundView];
    self.fakeBackgroundView.userInteractionEnabled = NO;
    [self sendSubviewToBack:self.fakeBackgroundView];
    
    self.titleTextAttributes = @{
                                 NSFontAttributeName: [UIFont fontWithName:@"NotoSansHans-DemiLight" size:16],
                                 NSForegroundColorAttributeName:[UIColor colorWithRed:57.0/255 green:207.0/255 blue:218.0/255 alpha:1]
                                 };
    
    //rgba(165, 195, 205, 1)
    self.tintColor = [UIColor colorWithRed:165.0/255 green:195.0/255 blue:205.0/255 alpha:1];
}

解釋 因?yàn)樵腘aviBar背景View下方有一條灰色的邊,這條邊不是用layer生成的,我沒搞明白是怎么實(shí)現(xiàn)的,所以直接將這個(gè)View隱藏掉了。順便吧shadowImage也換成空?qǐng)D。

這里的self.fakeBackgroundView是我們添加的背景,顏色是白色。這里我們將它移到最下層,并且觸摸屬性關(guān)掉,userInteractionEnabled設(shè)為NO。

titleTextAttributes這個(gè)屬性,是用來修改title的樣式的。

tintColor這個(gè)屬性,是用來修改導(dǎo)航條左右按鈕顏色的。

這些操作做完,還不夠。

我們無法通過暴露出來的接口修改左右按鈕的字體和位置。這也是我們選擇繼承而不是UIApperance的原因

繼承大殺器,高度自定義

- (void)didAddSubview:(UIView *)subview
{
    NSLog(@"%@",subview);
    if ([subview isKindOfClass:NSClassFromString(@"UINavigationButton")]) {
        if ([subview isKindOfClass:[UIButton class]]) {
            
            [(UIButton*)subview setAttributedTitle:[[NSAttributedString alloc] initWithString:[(UIButton*)subview titleForState:UIControlStateNormal] attributes:@{
                                                                                                                                                                   NSFontAttributeName: [UIFont fontWithName:@"AvenirNext-Regular" size:17],
                                                                                                                                                                   NSForegroundColorAttributeName:self.tintColor
                                                                                                                                                                   }] forState:UIControlStateNormal];
        }
    }
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull subview, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([subview isKindOfClass:NSClassFromString(@"UINavigationButton")]) {
            if ([subview isKindOfClass:[UIButton class]] && subview.frame.origin.x < self.frame.size.width/2) {
                [subview setFrame:({
                    CGRect rect = subview.frame;
                    rect.origin.x = 8;
                    rect.size.width = 69;
                    rect;
                })];
            }
        }
        
    }];
}

解釋 重寫- (void)didAddSubview:(UIView *)subview方法,檢測(cè)了系統(tǒng)控件根據(jù)NavigationItemNavigationBar添加按鈕這個(gè)事件,然后對(duì)按鈕進(jìn)行甄別,定制。

我們找到Cancel這個(gè)按鈕,他雖然是UINavigationButton類型,但是一定是繼承了UIButton,所以我們直接強(qiáng)轉(zhuǎn)成她的父類,修改其文字字體和frame。

重寫layoutSubviews這個(gè)方法,是為了實(shí)時(shí)更新我們的按鈕位置。這個(gè)其實(shí)也可以不更改的,但是我們的項(xiàng)目需求中,Cancel這個(gè)字段太長,字體變大以后導(dǎo)致了顯示不全,所以我們將這個(gè)做按鈕的frame變大了。

注意幾點(diǎn)

  1. NSClassFromString(@"UINavigationButton")這個(gè)方法是我們無法獲取內(nèi)部類的時(shí)候,獲取Class類型的方法。UINavigationButton這個(gè)類名是NSLog輸出時(shí)看到的。

  2. 這一段使用了特殊的語法糖,有興趣了解的參考這篇sunnyxx大神的博文,全文搜索關(guān)鍵字小括號(hào)內(nèi)聯(lián)復(fù)合表達(dá)式

[subview setFrame:({
                    CGRect rect = subview.frame;
                    rect.origin.x = 8;
                    rect.size.width = 69;
                    rect;
                })];

最后的實(shí)現(xiàn)效果。

FWBar.gif

結(jié)語

截屏的效果不是太好,細(xì)心的朋友可能會(huì)發(fā)現(xiàn),我們的FWBarTableView向上滑動(dòng)的過程中會(huì)漸出陰影。

我把這段代碼分享給大家,但是這段代碼偷懶沒用KVO,而是用了ReactiveCocoa這個(gè)龐大的龐大框架的小小功能,所以,就沒放到教程里。

- (void)didMoveToSuperview
{
    [super didMoveToSuperview];
    
    UIViewController *presentingViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    while (presentingViewController.presentedViewController) presentingViewController = presentingViewController.presentedViewController;

    __block BOOL has = NO;
    [[presentingViewController childViewControllers] enumerateObjectsUsingBlock:^(__kindof UIViewController * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isKindOfClass:[UINavigationController class]]) {
            [[obj childViewControllers] enumerateObjectsUsingBlock:^(__kindof UIViewController * _Nonnull obj2, NSUInteger idx, BOOL * _Nonnull stop) {
                if ([obj2 isKindOfClass:[UITableViewController class]]) {
                    has = YES;
                    UITableViewController* tVC = obj2;
                    if (self.tableViewOffsetDisposable) {
                        [self.tableViewOffsetDisposable dispose];
                    }
                    self.tableViewOffsetDisposable = [RACObserve(tVC.tableView, contentOffset) subscribeNext:^(id x) {
                        CGPoint p = [x CGPointValue];
                        
                        if (p.y <= 0 && p.y >= - 64) {
                            self.fakeBackgroundView.layer.shadowOpacity = fabs(64 + p.y) / 64 * 0.7;
                        }
                        else if (p.y > 0)
                        {
                            if (self.fakeBackgroundView.layer.shadowOpacity != 0.7) {
                                self.fakeBackgroundView.layer.shadowOpacity = 0.7;
                            }
                        }
                        else
                        {
                            if (self.fakeBackgroundView.layer.shadowOpacity != 0) {
                                self.fakeBackgroundView.layer.shadowOpacity = 0;
                            }
                        }
                    }];
                }
            }];
        }
    }];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,074評(píng)論 4 61
  • 一.項(xiàng)目引入依賴 在開始之前,首先給出GitHub上的鏈接 Githubhttps://github.com/Re...
    藍(lán)楓zeke閱讀 4,261評(píng)論 0 8
  • 我去到一個(gè)地方 到處是黑色的花 氣球都垂在地上 石頭都浮在半空 所有人只能倒立行走 臉貼地面,腳戴紅花 ...
    左小事界閱讀 139評(píng)論 0 0
  • 目錄 (五)初升的太陽 在連續(xù)四周奔波于公司和項(xiàng)目地之后,她終于病倒了。作為新官上任,剛接手了兩個(gè)新項(xiàng)目,出于自律...
    我從彩虹那邊來閱讀 483評(píng)論 0 1
  • 大螃蟹 ▲ 21周歲了,沒聽過很多的歌,總在向往詩和遠(yuǎn)方,眼前算不上茍且,平靜的生活只道是尋常阡陌。 很多的時(shí)候自...
    螃蟹螃蟹閱讀 478評(píng)論 5 1

友情鏈接更多精彩內(nèi)容