0 框架效果图
一 解说顺序
1 标题部分
2 内容显示部分
3 完好代码
4 知识补充
二 内容显示部分解析
1 搭建: 通过观察该部分执行情况,支持上下滑动,同一时候也支持左右滑动
2 分析一: 考虑内容显示的数据量比較大
—-> 2.1 做法: tableView採用循环利用
3 tableView的排列顺序: 设置scrollerView的偏移量为5个tableView的宽度(contentSize),将tableView依次从屏幕向右排列
4 观察:父控件scrollerView不能上下滑动,设置上下滑动的contentSize为0
6 scrollerView的frame决定可视范围;scrollerView的contentSize决定滑动范围
三 标题栏显示部分解析
1 观察:标题栏并不能滑动
—-> 1.1 结论:能够通过UIView来实现
4 选中后显示的下划线:採取用一个UIView来实现
四 标题栏相关说明和代码
1 通过观察,能够通过标题栏看究竟部的内容,说明标题栏是有透明度的,须要特别设置
2 设置标题的透明度(四种方法:三种可取,一种不可取)
—-> 2.1 方法一 :—->可取
titleView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];
—-> 2.2 方法二:—->可取
titleView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.5];
—-> 2.3 方法三: —->可取
titleView.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.5];
—-> 2.4 方法四:—->不可取
—-> 不可取原因:内部的子控件也会变透明
titleView.alpha = 0.3;
3 加入标题栏的代码
#pragma mark - 加入标题栏
- (void)setUpTitlesView
{
UIView *titleView = [[UIView alloc] init];
titleView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];
titleView.frame = CGRectMake(0, XFJ_navBar, XFJ_screenW, 35);
[self.view addSubview:titleView];
self.titleView = titleView;
[self setUptitlesButton];
[self setUpTitlesUnderLine];
}
1 採取for循环的方式创建
#pragma mark - 加入标题中的button
- (void)setUptitlesButton
{
NSArray *titles = @[@"全部",@"视频",@"声音",@"图片",@"段子"];
NSInteger count = titles.count;
CGFloat titleButtonX = 0;
CGFloat titleButtonY = 0;
CGFloat titleButtonW = self.titleView.XFJ_Width / count;
CGFloat titleButtonH = self.titleView.XFJ_Height;
for (NSInteger i = 0; i < count; i++) {
XFJTitleButton *titleButtons = [[XFJTitleButton alloc] init];
titleButtonX = i * titleButtonW;
titleButtons.tag = i;
titleButtons.frame = CGRectMake(titleButtonX, titleButtonY, titleButtonW, titleButtonH);
[titleButtons setTitle:titles[i] forState:UIControlStateNormal];
[titleButtons addTarget:self action:@selector(titleButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.titleView addSubview:titleButtons];
}
}
—> 1.1 直接通过改变颜色(传统的做法)
#pragma mark - 实现监听中的方法
- (void)titleButtonClick:(UIButton *)button
{
[self.previousButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
self.previousButton = button;
—> 1.2 传统方法的局限性:不方便改动文字的颜色
—> 1.3 方法一假设须要改动,就取决于设置的颜色
[titleButtons setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
[titleButtons setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
[titleButtons setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
[titleButtons setTitleColor:[UIColor redColor] forState:UIControlStateDisabled];
self.previousButton.enabled = YES;
button.enabled = NO;
self.previousButton = button;
2 该功能抽成一个方法,调用位置—>创建标题栏方法中调用
—> 代码:
#pragma mark - 加入标题button的选中线
- (void)setUpTitlesUnderLine
{
XFJTitleButton *firstTitleButton = self.titleView.subviews.firstObject;
UIView *underViewLine = [[UIView alloc] init];
CGFloat underViewLineX = 0;
CGFloat underViewLineH = 1;
CGFloat underViewLineY = self.titleView.XFJ_Height - underViewLine.XFJ_Height;
CGFloat underViewLineW = 0;
underViewLine.frame = CGRectMake(underViewLineX, underViewLineY, underViewLineW, underViewLineH);
underViewLine.backgroundColor = [firstTitleButton titleColorForState:UIControlStateSelected];
[self.titleView addSubview:underViewLine];
firstTitleButton.selected = YES;
self.previousButton = firstTitleButton;
[firstTitleButton.titleLabel sizeToFit];
self.underViewLine = underViewLine;
self.underViewLine.XFJ_Width = firstTitleButton.titleLabel.XFJ_Width + 10;
self.underViewLine.XFJ_centerX = firstTitleButton.XFJ_centerX;
}
//点击button移动下划线
[UIView animateWithDuration:0.25 animations:^{
//设置线的宽度
self.underViewLine.XFJ_Width = button.titleLabel.XFJ_Width + 10
//设置线的中心点和button对齐
self.underViewLine.XFJ_centerX = button.XFJ_centerX
1 重点:关闭自己主动调节内边距
3 设置contenSize,否则tableView将无法滚动
4 优化代码部分(后面补上)
5 整体代码部分:
#pragma mark - 加入内容的scrollerView
- (void)setUpAllChindView
{
self.automaticallyAdjustsScrollViewInsets = NO;
UIScrollView *contentView = [[UIScrollView alloc] init];
contentView.frame = self.view.bounds;
contentView.scrollsToTop = NO;
[self.view addSubview:contentView];
NSInteger count = self.childViewControllers.count;
for (NSInteger i = 0; i < count; i++) {
UIView *childView = self.childViewControllers[i].view;
childView.frame = CGRectMake(i * XFJ_screenW, 0, XFJ_screenW, XFJ_screenH);
[contentView addSubview:childView];
}
contentView.pagingEnabled = YES;
contentView.delegate = self;
contentView.contentSize = CGSizeMake(count * XFJ_screenW, 0);
contentView.showsHorizontalScrollIndicator = NO;
contentView.showsVerticalScrollIndicator = NO;
self.contentView = contentView;
}
九 标题与相应的tableView联动(一)
1 联动:开发中专业术语.意思是:通过改变一方某个状态,另外一方也会跟着改变
3 代码书写位置
—-> 2 联动三种方法:
//标题和子控制器view的联动问题(第一种方法)
self.contentView.contentOffset = CGPointMake(button.tag * XFJ_screenW, self.contentView.bounds.origin.y)
2.2 通过绑定的tag改动UIScrollView的偏移量(方法二)
//标题和子控制器view的联动问题(另外一种方法)-->直接改动偏移量
CGPoint offset = self.contentView.contentOffset
offset.x = button.tag * XFJ_screenW
self.contentView.contentOffset = offset
2.3 通过遍历标题栏的子控件(方法三:相对于上面2种比較好性能,可是假设button比較少,这方面问题也是不存在的)
//通过遍历的方法(方法三:相对于上面比較耗性能)--->遍历
NSInteger index = [self.titleView.subviews indexOfObject:button]
self.contentView.contentOffset = CGPointMake(index * XFJ_screenW,
self.contentView.bounds.origin.y)
十 tableView与相应的标题联动(二)
1 实现方案:直接通过代理就能够实现
2 思路: 通过偏移量和屏幕宽度的计算得到tableView的索引
4 代码:(代理方法:滑动完成的时候调用)
#pragma mark - 滑动完成的时候调用
#pragma mark - scrollerView的代理方法(设置拖动scrollerView与标题button联动)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSInteger index = scrollView.contentOffset.x / XFJ_screenW;
XFJTitleButton *titleButton = self.titleView.subviews[index];
[self titleButtonClick:titleButton];
}
十一 点击状态栏回到顶部
1 该功能苹果内部已经帮我们实现了(方法一)
2 使用这样的架构搭建的时候,点击状态栏,回到顶部的功能失效了
—> 6 代码:
for (NSInteger i = 0; i < self.childViewControllers.count; i++) {
UIViewController *childVC = self.childViewControllers[i];
if (![childVC isViewLoaded]) continue;
if (![childVC.view isKindOfClass:[UIScrollView class]]) continue;
UIScrollView *scrollView = (UIScrollView *)childVC.view;
scrollView.scrollsToTop = (i == index);
}
7 方法二:(不推荐使用)
—> 7.1 在创建一个窗体,仅仅有在创建一个窗体,才不会遮住状态栏,可是这样做会引起一系列的问题,所以不推荐使用,可是这样的功能还是须要的.比方,非常多电商应用都在界面中设置了一个能够移动而且点击的购物车,这就是利用新创建的窗体实现的.所以这样的方法慎用.
十二 全屏穿透
1 设置内边距实现全屏穿透的效果,让tableView全部的内容都能在内容区域显示,而且顶部内容和底部内容不会被tabBar和导航条遮住
2 实现代码:(必须在每个tableView控制器中都依次加入)
//设置view的颜色
self.tableView.backgroundColor = XFJ_randomColor
//设置内边距(内容的额外边距)
self.tableView.contentInset = UIEdgeInsetsMake(99, 0, 49, 0)
//设置tableView的滚动栏
self.tableView.scrollIndicatorInsets = self.tableView.contentInset
十三 加入全部的子控制器(这部分没什么好介绍的,看懂即可)
#pragma mark - 加入全部的tableView的view到内容的scrollerView
- (void)setUpAllTableView
{
//加入子控制器
[self addChildViewController:[[XFJAllViewController alloc] init]];
[self addChildViewController:[[XFJPassageViewController alloc] init]];
[self addChildViewController:[[XFJPictureViewController alloc] init]];
[self addChildViewController:[[XFJVideoViewController alloc] init]];
[self addChildViewController:[[XFJVoiceViewController alloc] init]];
}
十四 优化
1 tableView的懒载入
3 经过測试,假设按照以上的代码书写,能达到效果,可是我发现这样写的问题是tableView无法实现懒载入.原因是由于在第(八点),取出父控件中子控件的view的时候,在viewDidLoad中打印的结果显示,一開始就会创建5个tableView,所以不存在懒载入.
—-> 4.1 代码块一:
......}completion:^(BOOL finished) {
[self addChildVCIntoScrollView:index];
}];
4.2 方法:(内部做出了推断,假设父控件中存在view的时候,我们就不在创建)
#pragma mark - 加入相应的子控制器的view到scrollerView中
- (void)addChildVCIntoScrollView:(NSInteger)index
{
UIViewController *childVC = self.childViewControllers[index];
if ([childVC isViewLoaded]) return;
childVC.view.frame = self.contentView.bounds;
[self.contentView addSubview:childVC.view];
}
十五 知识点补充
1 frame.size.height:矩形框的高度
2 什么是tableView的内容(content)?
—> 2.1 cell
3 contentSize.height:内容的高度
4 contentOffset.y:内容的偏移量(frame的顶部-contentSize的顶部)
5 contentInset:内容周围的间距(内边距) frame:以父控件内容的左上角为坐标原点
十六 疑问
—> 原因:在viewDidLoad中载入的时候顺序出了问题
3 非常多人拖动tableView滑动的时候,看到了tableView之间有一根绿色的线条,这不是bug,是模拟器的原因.
十七 总结
1 该部分解说全然解析了当下流行框架和仿百思的框架的搭建步骤,里面都解析到了全部发生的问题,希望能帮到大家.
2 最后大家假设认为我的博客能满足大家的需求,希望能及时的给我留言,有什么问题的话,希望也及时给我留言.假设大家认为我的博客还能够的话,那么希望您关注我的官方博客,谢谢!!!!