一:父子控制器的应用:效果如图:
二:代码
1 #import "RHMainViewController.h" 2 #import "RHNewsTableViewController.h" 3 #import "RHLable.h" 4 static const CGFloat lableCount = 8; 5 static const CGFloat lableWidth = 80; 6 static const CGFloat lableHeight = 40; 7 #define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height 8 #define SCREENWIDTH [UIScreen mainScreen].bounds.size.width 9 @interface RHMainViewController ()<UIScrollViewDelegate> 10 /*顶部标题scrollView*/ 11 @property (nonatomic,weak)UIScrollView *titleScrollView; 12 /*底部的bottomScrollView*/ 13 @property (nonatomic,weak)UIScrollView *bottomScrollView; 14 @end 15 16 @implementation RHMainViewController 17 18 - (void)viewDidLoad { 19 [super viewDidLoad]; 20 21 //0:添加子控制器 22 [self setupChildViewControllers]; 23 24 //1:创建顶部标题的scrollView 25 [self setupTopScrollView]; 26 27 //2:创建底部的scrollView 28 [self setupBottomScrollView]; 29 30 //3:默认第一个新闻被选中 31 [self scrollViewDidEndScrollingAnimation:self.bottomScrollView]; 32 } 33 - (void)setupTopScrollView { 34 35 //1:设置自身属性 36 self.view.backgroundColor = [UIColor groupTableViewBackgroundColor]; 37 self.title = @"网易"; 38 self.automaticallyAdjustsScrollViewInsets = NO; 39 40 //2:创建顶部的标题滚动视图 41 UIScrollView *titleScroll = [[UIScrollView alloc]init]; 42 titleScroll.frame = CGRectMake(0, 64, self.view.frame.size.width, 40); 43 titleScroll.showsVerticalScrollIndicator = NO; 44 titleScroll.showsHorizontalScrollIndicator = NO; 45 titleScroll.bounces = NO; 46 self.titleScrollView = titleScroll; 47 [self.view addSubview:titleScroll]; 48 49 //3:创建顶部scrollView上的按钮 50 for (int i = 0; i <lableCount; i++) { 51 52 RHLable *lable = [[RHLable alloc]init]; 53 lable.frame = CGRectMake(i *lableWidth, 0, lableWidth, lableHeight); 54 [lable addGestureRecognizer: [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction:)]]; 55 lable.text = [self.childViewControllers[i] title]; 56 lable.tag = i; 57 [titleScroll addSubview:lable]; 58 if (i == 0) { 59 lable.sca = 1; 60 } 61 } 62 63 titleScroll.contentSize = CGSizeMake(lableCount *lableWidth, 0); 64 65 66 } 67 - (void)setupBottomScrollView { 68 69 //1:创建底部的scrollView 70 UIScrollView *bottomScrollView = [[UIScrollView alloc]init]; 71 bottomScrollView.frame = CGRectMake(0,CGRectGetMaxY(self.titleScrollView.frame) ,SCREENWIDTH , SCREENHEIGHT - 64 - 40); 72 bottomScrollView.bounces = NO; 73 bottomScrollView.showsVerticalScrollIndicator = NO; 74 bottomScrollView.showsHorizontalScrollIndicator = NO; 75 bottomScrollView.pagingEnabled = YES; 76 bottomScrollView.contentSize = CGSizeMake(lableCount *SCREENWIDTH, 0); 77 self.bottomScrollView = bottomScrollView; 78 bottomScrollView.delegate = self; 79 [self.view addSubview:bottomScrollView]; 80 81 } 82 83 - (void)setupChildViewControllers { 84 85 //新闻 86 RHNewsTableViewController *news = [[RHNewsTableViewController alloc]init]; 87 news.title = @"新闻"; 88 [self addChildViewController:news]; 89 90 //历史 91 RHNewsTableViewController *history = [[RHNewsTableViewController alloc]init]; 92 history.title = @"历史"; 93 [self addChildViewController:history]; 94 95 //阅读 96 RHNewsTableViewController *read = [[RHNewsTableViewController alloc]init]; 97 read.title = @"阅读"; 98 [self addChildViewController:read]; 99 100 //视频 101 RHNewsTableViewController *video = [[RHNewsTableViewController alloc]init]; 102 video.title = @"视频"; 103 [self addChildViewController:video]; 104 105 //图片 106 RHNewsTableViewController *image = [[RHNewsTableViewController alloc]init]; 107 image.title = @"图片"; 108 [self addChildViewController:image]; 109 110 //朋友 111 RHNewsTableViewController *friend = [[RHNewsTableViewController alloc]init]; 112 friend.title = @"朋友"; 113 [self addChildViewController:friend]; 114 115 //问答 116 RHNewsTableViewController *answer = [[RHNewsTableViewController alloc]init]; 117 answer.title = @"问答"; 118 [self addChildViewController:answer]; 119 120 //知识 121 RHNewsTableViewController *know = [[RHNewsTableViewController alloc]init]; 122 know.title = @"知识"; 123 [self addChildViewController:know]; 124 125 } 126 - (void)tapAction:(UITapGestureRecognizer*)tap { 127 128 //1:切换底部的scrollView的视图 129 NSUInteger index = tap.view.tag; 130 [self.bottomScrollView setContentOffset:CGPointMake(index *SCREENWIDTH, 0) animated:YES]; 131 132 } 133 /** 134 * scrollView结束了滚动动画以后就会调用这个方法(比如- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;方法执行的动画完毕后) 135 */ 136 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { 137 138 NSInteger index = scrollView.contentOffset.x / SCREENWIDTH; 139 RHLable *currentLable = self.titleScrollView.subviews[index]; 140 141 //1:当点击lable时,先将点击的lable自身居中 142 CGFloat moveX = currentLable.center.x - SCREENWIDTH *0.5; 143 CGFloat offset = self.titleScrollView.contentSize.width - SCREENWIDTH; 144 if (moveX < 0) moveX = 0; 145 if (moveX > offset) moveX = offset; 146 147 [self.titleScrollView setContentOffset:CGPointMake(moveX, 0) animated:YES]; 148 149 //2:设置其他lable为正常比例 150 for (RHLable *lable in self.titleScrollView.subviews) { 151 if (lable != currentLable) lable.sca = 0.0; 152 153 } 154 155 UIViewController *new = self.childViewControllers[index]; 156 //如果控制器的view已经加载过了,直接返回 157 if ([new isViewLoaded]) return; 158 new.view.frame = CGRectMake(index *SCREENWIDTH, 0, SCREENWIDTH, self.bottomScrollView.frame.size.height); 159 [self.bottomScrollView addSubview:new.view]; 160 161 } 162 /** 163 * 只要scrollView在滚动,就会调用 164 */ 165 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 166 167 CGFloat scale = scrollView.contentOffset.x / SCREENWIDTH; 168 if (scale < 0 || scale > self.childViewControllers.count -1) return; 169 NSInteger leftIndex = scale;//将浮点型数转换为整数,小数无论多少全部去掉 170 NSInteger rightIndex = leftIndex + 1; 171 172 //左侧的lable 173 RHLable *leftLable = self.titleScrollView.subviews[leftIndex]; 174 175 //右侧的lable 176 RHLable *rightLable = (rightIndex == self.titleScrollView.subviews.count) ? nil : self.titleScrollView.subviews[rightIndex]; 177 178 CGFloat rightScale = scale - leftIndex; 179 CGFloat leftScale = 1 - rightScale; 180 181 leftLable.sca = leftScale; 182 rightLable.sca = rightScale; 183 184 } 185 /** 186 * 手指松开scrollView后,scrollView停止减速完毕就会调用这个 187 */ 188 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { 189 190 [self scrollViewDidEndScrollingAnimation:scrollView]; 191 } 192 193 @end
1 #import "RHNewsTableViewController.h" 2 static NSString *const cellID = @"ID"; 3 @interface RHNewsTableViewController () 4 5 @end 6 7 @implementation RHNewsTableViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 12 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellID]; 13 14 } 15 16 17 #pragma mark - Table view data source 18 19 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 20 21 return 1; 22 } 23 24 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 25 26 return 30; 27 } 28 29 30 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 31 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath]; 32 cell.textLabel.text = [NSString stringWithFormat:@"%ld--------%@",(long)indexPath.row,self.title]; 33 return cell; 34 } 35 36 @end
1 #import <UIKit/UIKit.h> 2 3 @interface RHLable : UILabel 4 + (instancetype)lable; 5 @property (nonatomic,assign)CGFloat sca; 6 @end
1 #import "RHLable.h" 2 //247 86 176 3 @implementation RHLable 4 5 + (instancetype)lable { 6 7 return [[self alloc]init]; 8 } 9 10 - (instancetype)initWithFrame:(CGRect)frame { 11 12 if (self = [super initWithFrame:frame]) { 13 14 //1:设置自身的属性 15 self.font = [UIFont systemFontOfSize:15]; 16 self.textAlignment = NSTextAlignmentCenter; 17 self.textColor = [UIColor colorWithRed:RHRed green:RHGreen blue:RHBlue alpha:1]; 18 self.userInteractionEnabled = YES; 19 } 20 21 return self; 22 } 23 24 - (void)setSca:(CGFloat)sca { 25 26 _sca = sca; 27 28 // R G B 29 // 默认:0.4 0.6 0.7 30 // 红色:1 0 0 31 32 CGFloat redScale = RHRed + (1 - RHRed) *sca; 33 CGFloat greenScale = RHGreen - RHGreen *sca; 34 CGFloat blueScale = RHBlue - RHBlue *sca; 35 36 self.textColor = [UIColor colorWithRed:redScale green:greenScale blue:blueScale alpha:1]; 37 CGFloat fontScale = 1 +sca *0.3; 38 self.transform = CGAffineTransformMakeScale(fontScale, fontScale); 39 40 } 41 42 @end
#import<UIKit/UIKit.h> UIKIT_EXTERN const CGFloat RHRed; UIKIT_EXTERN const CGFloat RHGreen; UIKIT_EXTERN const CGFloat RHBlue; UIKIT_EXTERN const int Age; UIKIT_EXTERN NSString *const Name;
1 #import <UIKit/UIKit.h> 2 3 const CGFloat RHRed = 0.4; 4 const CGFloat RHGreen = 0.6; 5 const CGFloat RHBlue = 0.7; 6 const int Age = 10; 7 NSString *const Name = @"刚刚好";
三:知识点总结:
1:用static const定义基本数据,或是字符串来代替宏定义来节省内存 ,利用父子控制器,先将子控制器添加到父控制器上,此时父控制器最子控制器有一个强引用,只要父控制器在,则子控制器就会存在,不会销毁。子控制器在,子控制器就会对其上的view有一个强引用,子控制器View就不会销毁
2:当有导航栏的时候,又有scrollView或是继承scrollView的子控件如tableView或是collecttionView,系统会自动为滚动视图增加额外的64滚动区域,解决可以采取两种方法:1:self.automaticallyAdjustsScrollViewInsets = NO;默认为YES,自动调整 2:设置contentInset属性,减少其额外的滚动区域。
3:scrollView设置:titleScroll.showsVerticalScrollIndicator = NO; titleScroll.showsHorizontalScrollIndicator = NO设置隐藏两个滚动条后,则scrollView的子控件中就没有了这两个子控件,就同UIView,可以用scrollView.subViews,得到添加到scrollView上的子控件。其中属性用weak修饰,但是依然对象没有销毁,是因为该view添加到了self.view上了,则self.view对该scrollView有一个强引用,所以其对象不会销毁
4: lable.text = [self.childViewControllers[i] title];不用再去定义数组装着标题,去设置lable的text,任何属性都会生成下划线的成员变量,set和get方法,set方法赋完值后,若想在其他方法中获得该值,则可调用其属性的get方法。
5:scrollView不能滚动:1:scrollView.enablescroll 2:没有设置scrollView的contentSize 3:
setContentOffset animated 该方法设置scrollView的偏移量,自动产生动画,不用再去搞UIView的动画 4:NSInteger:整数,去除小数点。NSUinteger,修饰的数是大于等于0的。
6:scrollView的代理方法:1:scrollViewDidScroll:监听滚动,实时调用 2:scrollViewDidEndDecelerating:减速停止方法,当手指松开的时候调用 3:
scrollViewDidEndScrollingAnimation 当scrollView所有滚动动画停止的时候调用
7:网易首页骨架的实现思路:1:利用父子控制器,先添加子控制器到父控制器中 2:分别创建titleScrollView和bottomScrollView,并为titleScrollView添加手势,为bottomScrollView设置代理,当点击顶部的滚动视图时,点击的标题居中,切换底部的视图,通过tap.view.tag;可获得点击lable的index,也就是底部滚动视图所需要偏移的位置。用setContentOffset animated,实现底部滚动视图的动画偏移,在滚动视图动画停止的代理方法中scrollViewDidEndScrollingAnimation,设置点击lable的自身居中显示,用点击lable的自身中心点x与屏幕中心点x作比较,小于0.则不让其偏移,若是大于顶部滚动视图的最大偏移量(contentSize.width - SCREENWIDTH),则让其偏移量为最大偏移量。改变自身居中显示后,还要偏移底部滚动视图,需要将底部相应控制器的从父控制器的数组中取出,将view添加到底部的scrollView上,此时要加判断, if ([newVC isViewLoaded]) return;如果子控制器已经加载过了,就返回,避免重复添加view。3:当滚动底部的滚动视图时,顶部的滚动视图也要同步显示,在减速停止方法中,再调用scrollViewDidEndScrollingAnimation即可 4:监听scrollView的实时滚动,从而设置lable的颜色和字体变化,先通过偏移量求出scrollView偏移到第几页CGFloat类型,再做条件过滤,如果if (scale < 0 || scale > self.childViewControllers.count -1) return;偏移的第几页也有可能出现负数,或是大于子控件个数。(其实也可以不去设置此过滤条件)第二个限制条件,不能用scrollView.subViews.count,原因是控制器的view是懒加载的,当滚动时,此时view还没有添加到scrollView上。左右滑动时,求出左右的index,从顶部滚动视图的子控件数组中取出lable,求出左右lable的比例,赋值给lable,重写lable比例的set方法,颜色的改变,按比例值改变,在原来颜色的比例上,增加或是减少。字体的变大,可以设置lable自身transform按比例进行缩放,比例值计算,在1的基础上加上按比例计算的缩放值。5:在didscrollView执行完毕后后,又会调用scrollViewDidEndScrollingAnimation,在此方法中,遍历顶部滚动视图的子控件,让别的lable恢复比例的默认值。6:设置默认新闻被选中,则相当于调用了scrollViewDidEndScrollingAnimation方法,并且在创建lable时,默认i==0时,设置比例值为1
8:全局常量的设置:定义头文件,在创建相同类名空文件作为.m文件,.m文件负责定义常量,.h负责extern引用常量。
9:注册tableView的表格,就不用再去判断创建cell了,在数据源方法中,直接从缓存池中取可重用cell就可以了, [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellID];