国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

iOS定制UISearchBar導(dǎo)航欄同步iOS11的方法

2019-10-21 18:42:59
字體:
供稿:網(wǎng)友

系統(tǒng)原生的UISearchBar在iOS 11經(jīng)歷了一次變革,高度由原來的44變成了56 (使用默認(rèn)高度的估計(jì)都被坑了),樣式也發(fā)生了些微的變化,比如在未輸入狀態(tài)下圓角變化,放大鏡圖標(biāo)和文本的文字不再居中而是靠左了。具體看圖

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

 

一些主流App也常見在導(dǎo)航欄嵌入searchBar,以網(wǎng)易云音樂和知乎為例,左邊是主頁,右邊是搜索頁面 (注意光標(biāo))。

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄
 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

 

實(shí)現(xiàn)思路與案例

核心思想是設(shè)置導(dǎo)航欄的titleView和左右的barButtonItem。主要有3種方式

  1.  首頁導(dǎo)航欄的titleView使用button來實(shí)現(xiàn),搜索頁面使用searchBar。
  2. 首頁和搜索頁面導(dǎo)航欄的titleView都是用searchBar,searchBar的樣式針對兩個(gè)頁面做不同的修改。這種方式可以重用我們定制的searchBar,減少冗余。
  3. 首頁導(dǎo)航欄titleView使用button來實(shí)現(xiàn),搜索頁面的使用textField。這種方式更徹底,更靈活,相對也更復(fù)雜一些。

為什么上面的titleView說是button不是其他的?其他的當(dāng)然也可以實(shí)現(xiàn)。button自帶imageView和titleLabel,只需要設(shè)置偏移量更容易達(dá)到我們想要的,而且視圖層級更少,在流暢性方面更有保證些。

案例

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄
 

 

ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

網(wǎng)易云音樂首頁和搜索頁面的導(dǎo)航欄視圖層級,titleView都使用MCSearchBar來實(shí)現(xiàn),并且設(shè)置了導(dǎo)航欄左右兩邊的按鈕 。這類似上文所說的第二種思路。

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄 
 

 

ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

圖中可以清楚看到知乎首頁導(dǎo)航欄由2個(gè)button組成,搜索頁面使用了textField,這類似上文提到的第三種思路。

實(shí)戰(zhàn)

通過自定義SearchBar實(shí)現(xiàn)一個(gè)如下樣式的導(dǎo)航欄

 

 

ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

先自定義一個(gè)UISearchBar的初始化方法,觀察一下首頁和搜索頁的異同,像searchField的大小背景色是一致的,可以這部分可以直接給定,而placeholder是不一樣的,所以應(yīng)該在調(diào)用的時(shí)候提供。以此類推,新建一個(gè)OHSearchBar類,一個(gè)初始化方法

- (instancetype)initWithFrame:(CGRect)frame placeholder:(NSString *)placeholder textFieldLeftView:(UIImageView *)leftView showCancelButton:(BOOL)showCancelButton tintColor:(UIColor *)tintColor {  if (self = [super initWithFrame:frame]) {  self.frame = frame;  self.tintColor = tintColor; //光標(biāo)顏色  self.barTintColor = [UIColor whiteColor];  self.placeholder = placeholder;  self.showsCancelButton = showCancelButton;  self.leftView = leftView; // 用來代替左邊的放大鏡  [self setImage:[UIImage imageNamed:@"clear"] forSearchBarIcon:UISearchBarIconClear state:UIControlStateNormal]; // 替換輸入過程中右側(cè)的clearIcon } return self;}

新建一個(gè)首頁OHHomeViewController,設(shè)置導(dǎo)航欄的titleView和rightBarButton

// navigation buttom UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeSystem]; [messageButton setImage:[UIImage imageNamed:@"msg"] forState:UIControlStateNormal]; messageButton.bounds = CGRectMake(0, 0, 30, 30); UIBarButtonItem *messageBarButton = [[UIBarButtonItem alloc] initWithCustomView:messageButton]; self.navigationItem.rightBarButtonItem = messageBarButton;  // search bar UIImageView *leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"scan"]]; leftView.bounds = CGRectMake(0, 0, 24, 24); self.ohSearchBar = [[OHSearchBar alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 44)            placeholder:@"點(diǎn)擊我跳轉(zhuǎn)"          textFieldLeftView:leftView           showCancelButton:NO            tintColor:[UIColor clearColor]]; self.navigationItem.titleView = self.ohSearchBar;

讓我們來看下效果,左邊為iOS 9,右邊iOS 11

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

 

這時(shí)候可以看到幾處差異

  1. searchBar的高度
  2. searchBar的textField的放大鏡和文字位置
  3. textField的圓角不一致
  4. 更細(xì)心的還會發(fā)現(xiàn),textField的位置不一致

解決方法: 第一和第二個(gè)問題,判斷設(shè)備是否是iOS 11,若是則設(shè)置其高度,不是則讓其placeholder居左。關(guān)鍵代碼如下

if ([[UIDevice currentDevice] systemVersion].doubleValue >= 11.0) {  [[self.heightAnchor constraintEqualToConstant:44.0] setActive:YES]; } else {  [self setLeftPlaceholder]; }- (void)setLeftPlaceholder { SEL centerSelector = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"setCenter", @"Placeholder:"]); if ([self respondsToSelector:centerSelector]) {  BOOL centeredPlaceholder = NO;  NSMethodSignature *signature = [[UISearchBar class] instanceMethodSignatureForSelector:centerSelector];  NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];  [invocation setTarget:self];  [invocation setSelector:centerSelector];  [invocation setArgument:¢eredPlaceholder atIndex:2];  [invocation invoke]; }}

對于第三和第四個(gè)問題,用KVC獲取textField,并對其進(jìn)行定制。令textField位置、大小、圓角一致。

- (void)layoutSubviews{ [super layoutSubviews]; // search field UITextField *searchField = [self valueForKey:@"searchField"]; searchField.backgroundColor = DARK_BLUE_COLOR; searchField.textColor = [UIColor whiteColor]; searchField.font = [UIFont systemFontOfSize:16]; searchField.leftView = self.leftView; searchField.frame = CGRectMake(0, 8, SCREEN_WIDTH, 28); searchField.layer.cornerRadius = 5; searchField.layer.masksToBounds = YES; [searchField setValue:[UIColor whiteColor] forKeyPath:@"placeholderLabel.textColor"]; [self setValue:searchField forKey:@"searchField"];  self.searchTextPositionAdjustment = (UIOffset){10, 0}; // 光標(biāo)偏移量}

同樣的,先看下運(yùn)行效果

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

 

原本以為這下是沒什么問題的,結(jié)果簡直是坑

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

 

textFild的長度、位置、圓角都不一樣 解釋下這里出現(xiàn)的問題

觀察上方圖片上方的searchBar,會發(fā)現(xiàn)textField左邊是圓角,右邊是直角,說明是被截取的。導(dǎo)航欄titleView的范圍就劃分到了那個(gè)部分,而下邊的searchBar連rightBarButton都不放過,直接搶占了位置。推測這是由于iOS 11導(dǎo)航欄視圖層級變化產(chǎn)生的,可以這里了解下 www.jianshu.com/p/352f101d6… ,或者自行科普,不詳細(xì)展開。所以對于searchBar的size設(shè)置要小心了,盡量控制在合適的范圍。

textField的圓角是不一致的,自定義圓角大小時(shí),取消其本身的圓角樣式

searchField.borderStyle = UITextBorderStyleNone;

查看視圖層級會發(fā)現(xiàn),iOS 11以下,設(shè)置titleView,x的默認(rèn)坐標(biāo)居然是12,而iOS 11是0。所以設(shè)置textField的x坐標(biāo)的話,在iOS 11下必須多出12才會是一致的位置。

 

 
ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄 
 

 

ios,UISearchBar,iOS11,定制導(dǎo)航欄,導(dǎo)航欄

修改代碼上面的代碼

- (void)layoutSubviews{ [super layoutSubviews]; // search field UITextField *searchField = [self valueForKey:@"searchField"]; searchField.backgroundColor = DARK_BLUE_COLOR; searchField.textColor = [UIColor whiteColor]; searchField.font = [UIFont systemFontOfSize:16]; searchField.leftView = self.leftView; if (@available(iOS 11.0, *)) {  // 查看視圖層級,在iOS 11之前searchbar的x是12  searchField.frame = CGRectMake(12, 8, SCREEN_WIDTH*0.8, 28); } else {  searchField.frame = CGRectMake(0, 8, SCREEN_WIDTH*0.8, 28); } searchField.borderStyle = UITextBorderStyleNone; searchField.layer.cornerRadius = 5; searchField.layer.masksToBounds = YES; [searchField setValue:[UIColor whiteColor] forKeyPath:@"placeholderLabel.textColor"]; [self setValue:searchField forKey:@"searchField"];  self.searchTextPositionAdjustment = (UIOffset){10, 0}; // 光標(biāo)偏移量}

這時(shí)候就是我們想要的結(jié)果了。

首頁暫時(shí)告一段落,接著開始我們的搜索頁面。與首頁不同的是需要searchBar與searchController配合使用。新建一個(gè)OHSearchController類 添加一個(gè)屬性

@property (nonatomic, strong) OHSearchBar *ohSearchBar;

初始化代碼

- (instancetype)initWithSearchResultsController:(UIViewController *)searchResultsController searchBarFrame:(CGRect)searchBarFrame placeholder:(NSString *)placeholder textFieldLeftView:(UIImageView *)leftView showCancelButton:(BOOL)showCancelButton barTintColor:(UIColor *)barTintColor{ if (self = [super initWithSearchResultsController:searchResultsController]) {  self.ohSearchBar = [[OHSearchBar alloc] initWithFrame:searchBarFrame             placeholder:placeholder           textFieldLeftView:leftView            showCancelButton:YES             tintColor:barTintColor];    UIButton *button = [self.ohSearchBar valueForKey:@"cancelButton"];  button.tintColor = [UIColor whiteColor];  [button setTitle:@"取消" forState:UIControlStateNormal];  [self.ohSearchBar setValue:button forKey:@"cancelButton"]; } return self;}

接著是我們的視圖控制器OHSearchViewController

UIImageView *leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"search"]]; leftView.bounds = CGRectMake(0, 0, 24, 24); self.ohSearchController = [[OHSearchController alloc] initWithSearchResultsController:self                   searchBarFrame:CGRectMake(0, 0, SCREEN_WIDTH, 44)                    placeholder:@"請輸入搜索內(nèi)容進(jìn)行搜索"                  textFieldLeftView:leftView                   showCancelButton:YES                    barTintColor:BASE_BLUE_COLOR];  [self.ohSearchController.ohSearchBar becomeFirstResponder]; self.ohSearchController.ohSearchBar.delegate = self; [self.ohSearchController.ohSearchBar setLeftPlaceholder]; self.navigationItem.titleView = self.ohSearchController.ohSearchBar; self.navigationItem.hidesBackButton = YES;

完成這一步后到了交互環(huán)節(jié)了,點(diǎn)擊首頁的searchBar跳轉(zhuǎn)搜索頁面,點(diǎn)擊搜索頁面的取消按鈕返回到首頁。 首頁設(shè)置searchbar的代理,并完成一下代理方法

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar { OHSearchViewController *ohSearchViewController = [[OHSearchViewController alloc] init]; [self.navigationController pushViewController:ohSearchViewController animated:NO]; return YES;}

搜索頁設(shè)置searchbar的代理,并完成一下代理方法

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { [self.navigationController popViewControllerAnimated:NO];}- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [self.ohSearchController.ohSearchBar resignFirstResponder]; // 讓取消按鈕一直處于激活狀態(tài) UIButton *cancelBtn = [searchBar valueForKey:@"cancelButton"]; cancelBtn.enabled = YES;}

這時(shí)候問題又出現(xiàn)了,點(diǎn)擊搜索頁面的取消按鈕,沒有跳回首頁而是還在這個(gè)頁面。但是可以看到屏幕的閃動。通過打印消息發(fā)現(xiàn),點(diǎn)了取消按鈕,執(zhí)行了首頁的- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar方法。 仔細(xì)推敲之后想明白了原因是沒有取消第一響應(yīng)者,加上導(dǎo)航欄的交互機(jī)制,pop到上個(gè)頁面的時(shí)候并不會進(jìn)行頁面刷新導(dǎo)致了這個(gè)問題。 解決辦法在首頁要push搜索頁面的時(shí)候取消第一響應(yīng)者

- (void)viewWillDisappear:(BOOL)animated { [self.ohSearchBar resignFirstResponder];}

到此,便大功告成了。可以看下源碼加深理解。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到IOS開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 睢宁县| 云霄县| 隆林| 呼和浩特市| 宝坻区| 东台市| 龙门县| 新密市| 额尔古纳市| 林甸县| 托克逊县| 长子县| 仙桃市| 铜山县| 宿迁市| 永福县| 嘉义市| 太谷县| 丹东市| 连南| 康保县| 枣阳市| 淮安市| 洛阳市| 浮山县| 喀喇沁旗| 霍林郭勒市| 南郑县| 留坝县| 南漳县| 沧源| 黎川县| 青铜峡市| 松潘县| 临漳县| 大石桥市| 大洼县| 吐鲁番市| 横山县| 石台县| 大安市|