今天再來給你們帶來一個開發中經常使用到的視圖控制器,在不少應用中,可能都會遇到這樣的一個需求:表視圖控制器最上方有一個頭圖控件,當表格視圖滑動在頂部時,導航欄透明,當表格視圖逐漸向下滑動時,導航欄漸漸出現,而且在滑動期間,頭圖會展現相關的漸變更畫效果。之前常常會遇到這樣的需求,但從沒有整理與封裝完善,此次將其封裝成完整的控件,不管有無導航,均可以很好的支持,方便之後使用也提供給須要的朋友。數組
在設計控件以前,咱們應該先編寫控件的頭文件,頭文件中將控件須要的屬性和方法列舉,以後再按定義好的接口一步步的來實現控件的編寫設計,這樣能夠結構清晰,而且不會顯得無從下手,控件的頭文件設計以下:app
// // YHBaseHeaderAnimatedViewController.h // YHBaseFoundationTest // // Created by vip on 16/4/26. // Copyright © 2016年 jaki.zhang. All rights reserved. /* * 這個視圖控制器建立出帶縮放頭圖效果的視圖控制器 * tip: * 1.這個視圖控制器若是是被導航push出來的 則內部會使用假導航進行漸隱模擬 * 2.這個視圖控制器若是是被present出來的 則不會出現假導航欄 * 3.這個視圖控制器中自帶一個TableView 設置TableView的頭圖不會影響原動畫效果 * */ #import <UIKit/UIKit.h> /** * 這個枚舉設置頭圖動畫滑動的速度等級 */ typedef enum { YHBaseHeaderAnimatedLevelSlow, YHBaseHeaderAnimatedLevelNormal, YHBaseHeaderAnimatedLevelFast }YHBaseHeaderAnimatedLevel; @interface YHBaseHeaderAnimatedViewController : UIViewController<UITableViewDataSource,UITableViewDelegate> @property(nonatomic,strong,readonly)UITableView * tableView; /** * 設置動畫頭圖圖片 */ @property(nonatomic,strong)UIView * animatedHeaderView; /** * 設置TableView的頭視圖 * * 注意:設置tableView的頭視圖不可以在使用tableHeatherView方法 要使用這個屬性設置 * */ @property(nonatomic,strong)UIView * tableHeaderView; /** * 設置動畫頭圖高度 * * 這個屬性若是不設置或者設置爲0 則默認會使用設置的image圖片比例 * */ @property(nonatomic,assign)CGFloat headerHeight; /** * * 設置動畫滑動速率 */ @property(nonatomic,assign)YHBaseHeaderAnimatedLevel animatedlevel; /** * * 設置頭圖可方法的最大scrollView偏移量 默認爲40 * */ @property(nonatomic,assign)CGFloat maxScrollOffset; /** * 設置是否帶漸隱效果 * */ @property(nonatomic,assign)BOOL alphaAnimated; /** * 設置最小漸變到的alpha漸隱值 <0 >1之間 默認爲0.5 * */ @property(nonatomic,assign)CGFloat minAlpha; /** * * 是否顯示毛玻璃模糊效果 * */ @property(nonatomic,assign)BOOL bluerAnimated; /** * * 設置最大小模糊度 默認爲1 * */ @property(nonatomic,assign)CGFloat maxBluer; /** * 設置導航欄顏色 默認白色 * */ @property(nonatomic,strong)UIColor * naviColor; /** * 設置導航左側按鈕數組 若是不設置 會自動帶一個返回按鈕 * */ @property(nonatomic,strong)NSArray * leftBarButtons; /** * 設置導航左側按鈕數組 若是不設置 會自動帶一個返回按鈕 * */ @property(nonatomic,strong)NSArray * rightBarButtons; /** * 這個方法在修改了頭圖相關屬性後 須要調用刷新 * * 注意:若是從新設置了TableView的tableheaderView屬性 也須要調用這個方法刷新 * */ -(void)reloadAnimatedView; @end
在設計這個控件時,我主要考慮兩個須要優化的地方,第一是這個控制器在不一樣的場景下可能會有不一樣的結構,例如在導航結構中被push出來或者經過模態跳轉被present出來,我在這個控件的實現時作了兼容,實際上不管有無導航,控件內部都沒有使用系統的導航欄,而是模擬實現了一個自定義的導航欄來與系統的導航無縫銜接。優化
.m文件中實現的代碼以下:動畫
#import "YHBaseHeaderAnimatedViewController.h" @interface YHBaseHeaderAnimatedViewController () { //承載視圖 UIView * _privteBGHeaderView; //寬高比例 CGFloat _privteRate; //原始寬高 CGFloat _privteOriWidth; CGFloat _privteOriHeught; UIVisualEffectView * _blurView; UINavigationBar * _naviBar; } @end @implementation YHBaseHeaderAnimatedViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.edgesForExtendedLayout = UIRectEdgeNone; _tableView = [[UITableView alloc]initWithFrame:self.view.frame style:UITableViewStylePlain]; [self.view addSubview:_tableView]; _tableView.delegate=self; _tableView.dataSource=self; [self YHCreatView]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } //對導航進行處理 -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; if (self.navigationController) { [self.navigationController setNavigationBarHidden:YES animated:YES]; [self showNavigationBar]; } } -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; if (self.navigationController) { [self.navigationController setNavigationBarHidden:NO animated:YES]; } } -(void)showNavigationBar{ if (_naviBar==nil) { _naviBar = [[UINavigationBar alloc]init]; [self.view addSubview:_naviBar]; _naviBar.frame = CGRectMake(0, 0, self.view.frame.size.width, 64); [_naviBar setBackgroundImage:[UIImage imageNamed:@"clear"] forBarMetrics:UIBarMetricsDefault]; [_naviBar setShadowImage:[UIImage imageNamed:@"clear"]]; _naviBar.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0]; UINavigationItem * item = [[UINavigationItem alloc]initWithTitle:self.title]; _naviBar.items = @[item]; item.leftBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"返回" style:UIBarButtonItemStyleDone target:self action:@selector(popToLast)]; } if (self.animatedHeaderView==nil) { _naviBar.hidden=YES; }else{ _naviBar.hidden=NO; } } -(void)popToLast{ [self.navigationController popViewControllerAnimated:YES]; } -(void)YHCreatView{ if (self.maxScrollOffset==0) { self.maxScrollOffset=40; } if (self.minAlpha==0) { self.minAlpha = 0.5; } if (self.maxBluer==0) { self.maxBluer = 1; } _privteBGHeaderView = [[UIView alloc]init]; _privteBGHeaderView.backgroundColor = [UIColor clearColor]; self.tableView.backgroundColor = [UIColor clearColor]; _blurView = [[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; [self reloadAnimatedView]; } -(void)reloadAnimatedView{ CGFloat viewH=0; CGFloat aniH=0; for (UIView * view in _privteBGHeaderView.subviews) { [view removeFromSuperview]; } if (self.tableHeaderView) { viewH = viewH+self.tableHeaderView.bounds.size.height; [_privteBGHeaderView addSubview:self.tableHeaderView]; } if (self.animatedHeaderView) { _privteRate = self.animatedHeaderView.frame.size.width/self.animatedHeaderView.frame.size.height; [self.animatedHeaderView addSubview:_blurView]; _blurView.frame= self.animatedHeaderView.bounds; _blurView.alpha=0; _privteOriWidth = self.animatedHeaderView.frame.size.width; _privteOriHeught = self.animatedHeaderView.frame.size.height; if (self.headerHeight!=0) { viewH+=self.headerHeight; aniH = self.headerHeight; }else{ viewH+=self.view.frame.size.width/self.animatedHeaderView.bounds.size.width*self.animatedHeaderView.frame.size.height; aniH = self.animatedHeaderView.bounds.size.height; } [self.view insertSubview:self.animatedHeaderView atIndex:0]; } self.tableHeaderView.frame=CGRectMake(0, aniH, self.tableHeaderView.frame.size.width, self.tableHeaderView.frame.size.height); _privteBGHeaderView.frame=CGRectMake(0, 0, self.view.frame.size.width, viewH); self.tableView.tableHeaderView = _privteBGHeaderView; } -(void)setAnimatedHeaderView:(UIView *)animatedHeaderView{ if (animatedHeaderView==nil) { if (_animatedHeaderView) { [_animatedHeaderView removeFromSuperview]; } } _animatedHeaderView = animatedHeaderView; } -(void)setMinAlpha:(CGFloat)minAlpha{ if (minAlpha<=0) { minAlpha=0.001; } if (minAlpha>=1) { minAlpha=0.999; } _minAlpha=minAlpha; } -(void)setMaxBluer:(CGFloat)maxBluer{ if (maxBluer<=0) { maxBluer = 0.001; } if (maxBluer>=1) { maxBluer = 0.999; } _maxBluer = maxBluer; } -(void)setNaviColor:(UIColor *)naviColor{ _naviColor = naviColor; _naviBar.backgroundColor = naviColor; } -(void)setLeftBarButtons:(NSArray *)leftBarButtons{ _naviBar.topItem.leftBarButtonItems = leftBarButtons; _leftBarButtons = leftBarButtons; } -(void)setRightBarButtons:(NSArray *)rightBarButtons{ _naviBar.topItem.rightBarButtonItems = rightBarButtons; _rightBarButtons = rightBarButtons; } -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ if (self.animatedHeaderView==nil) { return; } if (self.tableView==scrollView) { //獲取到偏移量 默認兩倍 CGFloat offset = scrollView.contentOffset.y*2; //若是小於0 則進行形變拉伸操做 if (offset<=0) { if (offset<-self.maxScrollOffset*2) { }else{ CGFloat height = _privteOriHeught+abs((int)offset); CGFloat width = height*_privteRate; self.animatedHeaderView.frame = CGRectMake(self.view.frame.size.width/2-width/2, offset/2, width, height); } if (_naviBar) { if (_naviBar.shadowImage==nil) { [_naviBar setShadowImage:[UIImage imageNamed:@"clear"]]; } } }else{ //若是大於零 進行推出操做 if (self.animatedlevel==YHBaseHeaderAnimatedLevelSlow) { //慢速 self.animatedHeaderView.frame = CGRectMake(0, -offset/8, self.animatedHeaderView.frame.size.width, self.animatedHeaderView.frame.size.height); }else if(self.animatedlevel==YHBaseHeaderAnimatedLevelFast){ //快速 self.animatedHeaderView.frame = CGRectMake(0, -offset/2, self.animatedHeaderView.frame.size.width, self.animatedHeaderView.frame.size.height); }else{ //正常 self.animatedHeaderView.frame = CGRectMake(0, -offset/4, self.animatedHeaderView.frame.size.width, self.animatedHeaderView.frame.size.height); } //進行漸隱動畫處理 CGFloat tmp = offset/2/_privteOriHeught; if (self.alphaAnimated) { self.animatedHeaderView.alpha = 1-(1-self.minAlpha)*tmp; } //進行模糊動畫 if (self.bluerAnimated) { _blurView.alpha = self.maxBluer*tmp; } //進行導航顯示 if (_naviBar) { _naviBar.backgroundColor = [_naviBar.backgroundColor colorWithAlphaComponent:tmp]; if (_naviBar.shadowImage) { [_naviBar setShadowImage:nil]; } } } } } @end
在使用時,建立一個視圖控制器繼承於它,在其viewDidLoad方法中進行一些簡單的設置便可,以下:atom
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. //設置頭圖 UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 200)]; imageView.image = [UIImage imageNamed:@"image"]; self.animatedHeaderView = imageView; //設置tableView的頭視圖 UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 30)]; label.backgroundColor = [UIColor purpleColor]; label.textColor = [UIColor whiteColor]; label.textAlignment =NSTextAlignmentCenter; label.text = @"下面進行功能演示"; self.tableHeaderView = label; [self reloadAnimatedView]; }
我寫了一個完整的演示Demo,Demo中有完整的功能演示,須要的朋友能夠自行下載:http://pan.baidu.com/s/1c1VKT00。spa
專一技術,熱愛生活,交流技術,也作朋友。設計
——琿少 QQ羣:203317592code