接著上週的專案, 在上週我別出心裁的在自定義TabbarController中加入了自定義轉場動畫, 受到了大家廣泛的喜愛, 再次表示感激, 今天我們繼續實現LifestyleViewController的第二個功能漸變導航欄!!
漸變導航欄, 現在很多專案裡都有這個功能, 我們就把這個功能整合到我們的專案中來; 根據設計圖紙需求, 我們需要在輪播圖下面有一個搜尋欄, 搜尋欄根據滑動偏移到導航欄之上.
具體怎麼實現呢, Easy啦~ 不急,我們一步一步來.
建立搜尋欄Cell
首先開啟我們的專案先在輪播圖Cell下建立一個搜尋欄Cell 並新增子控制元件.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
- (UIImageView *)hotSpotsImageView { if (!_hotSpotsImageView) { _hotSpotsImageView = [UIImageView new]; _hotSpotsImageView.image = [UIImage imageNamed:@"Hot Spots"]; } return _hotSpotsImageView; } - (void)layoutSubviews { [super layoutSubviews]; CGFloat padding = kSpace; CGFloat hotSpotsImageViewX = padding; CGFloat hotSpotsImageViewW = 90; CGFloat hotSpotsImageViewH = 20; CGFloat hotSpotsImageViewY = self.height - hotSpotsImageViewH - 5; self.hotSpotsImageView.frame = CGRectMake(hotSpotsImageViewX, hotSpotsImageViewY, hotSpotsImageViewW, hotSpotsImageViewH); } |
這時你可能會問 為什麼不在Cell中新增TextField之類的, 由於我們的效果,之後再向您揭曉;
控制器 多Cell設計
這時回到控制器, 但是控制器中不止一種Cell, 我們怎麼來設計呢?? 我的實現方法是KeysArr, 那什麼是KeysArr呢,我們來看程式碼.
首先我們需要建立一個全域性類 (這個寫法和上週的 投機流 自定義轉場有異曲同工之妙)
建立全域性類
全域性類中的每一個Key對應著你的一個Cell
.h
1 2 |
extern NSString * const kSQLifestyleBannerKey; extern NSString * const kSQLifestyleSearchKey; |
.m
1 2 |
NSString * const kSQLifestyleBannerKey = @"輪播圖"; NSString * const kSQLifestyleSearchKey = @"熱點"; |
keys陣列
接著我們建立一個陣列來持有這些key;
1 |
@property (nonatomic,strong) NSArray * keysArr; |
1 2 3 4 5 6 7 8 |
- (NSArray *)keysArr { if (!_keysArr) { _keysArr = @[kSQLifestyleBannerKey, kSQLifestyleSearchKey]; } return _keysArr; } |
Tableview delegate mothod
最後在代理方法中進行判斷
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 |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.keysArr.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString * const key = self.keysArr[indexPath.row]; if (key == kSQLifestyleBannerKey) { SQLifestyleBannerCell * cell = [SQLifestyleBannerCell cellWithTableView:tableView]; return cell; } if (key == kSQLifestyleSearchKey) { SQLifestyleSearchCell * cell = [SQLifestyleSearchCell cellWithTableView:tableView]; return cell; } return nil; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSString * const key = self.keysArr[indexPath.row]; if (key == kSQLifestyleBannerKey) { return [SQLifestyleBannerCell cellHeight]; } if (key == kSQLifestyleSearchKey) { return [SQLifestyleSearchCell cellHeight]; } return 0; } |
這樣當不需要某個cell顯示的時候,只需要將keys從KeysArr中移除即可, 是不是很方便!!
建立搜尋欄View
這裡需要提醒大家的一點, 當你在自定義View的時候最好要實現initWithFrame
和initWithCoder
兩個方法, 這樣無論是用純程式碼還是Xib,Storyboard使用自定義View時都能夠直接載入!!
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 |
- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupSubviews]; } return self; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self setupSubviews]; } return self; } - (UITextField *)searchBarTextField { if (!_searchBarTextField) { _searchBarTextField = [UITextField new]; _searchBarTextField.backgroundColor = [UIColor whiteColor]; _searchBarTextField.layer.borderColor = KC05_dddddd.CGColor; _searchBarTextField.layer.borderWidth = 0.5f; _searchBarTextField.layer.cornerRadius = 5; _searchBarTextField.layer.masksToBounds= YES; _searchBarTextField.placeholder = @"Searching for something new"; _searchBarTextField.leftView = self.magnifierImageView; _searchBarTextField.leftViewMode = UITextFieldViewModeAlways; [_searchBarTextField setValue:KC04_999999 forKeyPath:@"placeholderLabel.textColor"]; } return _searchBarTextField; } - (UIImageView *)magnifierImageView { if (!_magnifierImageView) { _magnifierImageView = [UIImageView new]; _magnifierImageView.image = [UIImage imageNamed:@"fa-search"]; _magnifierImageView.frame = CGRectMake(0, 0, 34, 34); _magnifierImageView.contentMode = UIViewContentModeCenter; } return _magnifierImageView; } - (void)setupSubviews { [self addSubview:self.searchBarTextField]; } - (void)layoutSubviews { [super layoutSubviews]; CGFloat searchBarTextFieldX = 0; CGFloat searchBarTextFieldY = 0; CGFloat searchBarTextFieldW = self.width; CGFloat searchBarTextFieldH = 34; self.searchBarTextField.frame = CGRectMake(searchBarTextFieldX, searchBarTextFieldY, searchBarTextFieldW, searchBarTextFieldH); } |
實現位移漸變
重於到今天的重頭戲了, 我們來實現位移漸變!! 上面的自定義View 我們並不是將其新增到Cell之中, 而是將他新增到navigationController.view
之上!!
建立兩個自定義View
1 2 |
@property (nonatomic,strong) SQLifestyleSearchBarView * titleView; @property (nonatomic,strong) SQLifestyleSearchBarView * searchBarView; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
- (SQLifestyleSearchBarView *)titleView { if (!_titleView) { _titleView = [SQLifestyleSearchBarView new]; _titleView.frame = self.navigationController.navigationBar.frame; } return _titleView; } - (SQLifestyleSearchBarView *)searchBarView { if (!_searchBarView) { _searchBarView = [SQLifestyleSearchBarView new]; } return _searchBarView; } |
其中一個的frame = self.navigationController.navigationBar.frame
並將其新增到titleView
中!! 另一個將其載入navigationController.view
中!! 並在viewWillLayoutSubviews
中設定佈局!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
- (void)loadView { [super loadView]; [self.navigationItem setTitleView:self.titleView]; [self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[UIColor clearColor]] forBarMetrics:UIBarMetricsDefault]; [self.navigationController.navigationBar setShadowImage:[UIImage imageWithColor:[UIColor clearColor]]]; } - (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.tableView]; [self.navigationController.view addSubview:self.searchBarView]; } - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; CGFloat searchBarViewX = kSpace; CGFloat searchBarViewW = self.titleView.width; CGFloat searchBarViewH = self.titleView.height; CGFloat searchBarViewY = kScaleLength(210) + searchBarViewH - self.tableView.contentOffset.y - searchBarViewH; self.searchBarView.frame = CGRectMake(searchBarViewX, searchBarViewY, searchBarViewW, searchBarViewH); } |
監聽偏移
我們將設定導航欄背景顏色的方法從LoadView移到scrollViewDidScroll
中來
這裡需要和大家細說一下監聽偏移漸變,其實很簡單,就是一個公式而已 float alpha = 1 - (offset) - scrollView.contentOffset.y) / offset);
其中的offset 指的是y軸方向從初始值viewWillLayoutSubviews
中的初始設定 到導航欄的位移!!
每滑動下重新呼叫viewWillLayoutSubviews
方法重新佈局, 當其到達位移點的時候, 兩個View進行交換就達到了 預期的效果!!
1 2 3 4 5 6 7 8 |
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { [self viewWillLayoutSubviews]; [[[UIApplication sharedApplication] keyWindow] endEditing:YES]; float alpha = 1 - ((kScaleLength(190.5) - scrollView.contentOffset.y) / kScaleLength(190.5)); [self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[KC01_57c2de colorWithAlphaComponent:alpha > 0.95f ? 0.95f : alpha]] forBarMetrics:UIBarMetricsDefault]; self.titleView.hidden = scrollView.contentOffset.y > kScaleLength(190.5) ? NO : YES; self.searchBarView = !titleView.hidden; } |
對位移漸變的封裝
上面的程式碼看到暈暈乎乎,講的不清不楚!! 我們來講這個功能封裝一下, 先建立一個UIViewController的Catagory 實現方法!!
- scrollView: 傳入需要位移的scrollView;
- titleView: 傳入導航欄上的titleView;
- movableView: 傳入需要移動的自定義View;
- offset: 傳入y軸方向從初始值到導航欄的位移;
- color: 傳入導航欄顏色
1 2 3 4 5 6 7 |
- (void)navigationBarGradualChangeWithScrollView:(UIScrollView *)scrollView titleView:(UIView *)titleView movableView:(UIView *)movableView offset:(CGFloat)offset color:(UIColor *)color { float alpha = 1 - ((offset - scrollView.contentOffset.y) / offset); [self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[color colorWithAlphaComponent:alpha > 0.95f ? 0.95f : alpha]] forBarMetrics:UIBarMetricsDefault]; titleView .hidden = scrollView.contentOffset.y > offset ? NO : YES; movableView.hidden = !titleView .hidden; } |
這樣我們在呼叫的時候就簡單明瞭多了!! 以後做到這個功能的時候可以直接拿來用了!!
1 2 3 4 5 |
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { [self viewWillLayoutSubviews]; [[[UIApplication sharedApplication] keyWindow] endEditing:YES]; [self navigationBarGradualChangeWithScrollView:scrollView titleView:self.titleView movableView:self.searchBarView offset:kScaleLength(190.5) color:KC01_57c2de]; } |
模擬效果
為了能看到效果 我們在控制器中多加幾個cell 方法很簡單隻要在Key陣列中多加幾個物件即可! 並在key == @"" 時載入如下Cell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
- (NSArray *)keysArr { if (!_keysArr) { _keysArr = @[kSQLifestyleBannerKey, kSQLifestyleSearchKey, @"",@"",@"",@"",@"", @"",@"",@"",@"",@"", @"",@"",@"",@"",@"", @"",@"",@"",@"",@""]; } return _keysArr; } static NSString * identifier = @"cell"; UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; } cell.textLabel.text = @"https://coderZsq.github.io"; return cell; |
好了 我們來看下顯示效果吧~~
最終顯示