最近项目中用到了模仿网易新闻的标题栏,尽管现在gitHub和code4app上有好多第三方,但是还是想搞清楚是怎么实现的,特此记录。有可以滚动和不可以滚动的。
一 、模仿网易:
效果:
代码:
#import "WangYiMainVC.h"
#import "OneVC.h"
#import "TwoVC.h"
#import "ThreeVC.h"
#import "FourVC.h"
static CGFloat const labelW = 100;
static CGFloat const radio = 1.3;
@interface WangYiMainVC ()<UIScrollViewDelegate>
@property (nonatomic , weak) UIScrollView *titleScrollView;
@property (weak , nonatomic) UIScrollView *contentScrollView;
@property (nonatomic, weak) UILabel *selLabel;
@property (nonatomic, strong) NSMutableArray *titleLabels;
@end
@implementation WangYiMainVC
/*
网易新闻实现步骤:
1.搭建结构(导航控制器)
* 自定义导航控制器根控制器NewsViewController
* 搭建NewsViewController界面(上下滚动条)
* 确定NewsViewController有多少个子控制器,添加子控制器
2.设置上面滚动条标题
* 遍历所有子控制器
3.监听滚动条标题点击
* 3.1 让标题选中,文字变为红色
* 3.2 滚动到对应的位置
* 3.3 在对应的位置添加子控制器view
4.监听滚动完成时候
* 4.1 在对应的位置添加子控制器view
* 4.2 选中子控制器对应的标题
*/
// 懒加载
- (NSMutableArray *)titleLabels
{
if (_titleLabels == nil) {
_titleLabels = [NSMutableArray array];
}
return _titleLabels;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"网易";
self.view.backgroundColor = [UIColor whiteColor];
// iOS7会给导航控制器下所有的UIScrollView顶部添加额外滚动区域
// 不想要添加
self.automaticallyAdjustsScrollViewInsets = NO;
//1.初始化子控制器
[self setUpChildViewControllers];
[self setUpSubViews];
//设置标题栏
[self setUpTitleViews];
}
-(void)setUpSubViews{
//设置标题栏
UIScrollView *titleView = [[UIScrollView alloc] init];
titleView.width = self.view.width;
// titleView.backgroundColor = [UIColor redColor];
titleView.height = 44;
titleView.x = 0;
titleView.y = 64;
self.titleScrollView = titleView;
// 设置标题滚动条
NSInteger count = self.childViewControllers.count;
self.titleScrollView.contentSize = CGSizeMake(count * labelW, 0);
self.titleScrollView.showsHorizontalScrollIndicator = NO;
[self.view addSubview:titleView];
UIScrollView *contentView = [[UIScrollView alloc] init];
contentView.width = self.view.width;
// contentView.backgroundColor = [UIColor blueColor];
contentView.height = self.view.height - self.titleScrollView.height - 44;
contentView.x = 0;
contentView.y = self.titleScrollView.height + self.titleScrollView.y;
self.contentScrollView = contentView;
[self.view addSubview:contentView];
// 设置内容滚动条
self.contentScrollView.contentSize = CGSizeMake(count * XMGScreenW, 0);
// 开启分页
self.contentScrollView.pagingEnabled = YES;
// 没有弹簧效果
self.contentScrollView.bounces = NO;
// 隐藏水平滚动条
self.contentScrollView.showsHorizontalScrollIndicator = NO;
// 设置代理
self.contentScrollView.delegate = self;
}
//设置titleScrollerView
-(void)setUpTitleViews{
NSUInteger count = self.childViewControllers.count;
//设置标题
CGFloat lableX = 0;
CGFloat lableY = 0;
CGFloat lableH = 44;
for ( int i = 0; i<count; i++) {
UILabel *lable =[[UILabel alloc] init];
// lable.backgroundColor = [UIColor redColor];
lableX = i * labelW;
//设置尺寸
lable.frame = CGRectMake(lableX, lableY, labelW, lableH);
//设置lable文字
UIViewController *vc = self.childViewControllers[i];
lable.text = vc.title;
// 设置高亮文字颜色
lable.highlightedTextColor = [UIColor redColor];
// 文字居中
lable.textAlignment = NSTextAlignmentCenter;
// 设置label的tag
lable.tag = i;
// 添加到titleLabels数组
[self.titleLabels addObject:lable];
// 添加点按手势
lable.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(titleClick:)];
[lable addGestureRecognizer:tap];
// 默认选中第0个label
if (i == 0) {
[self titleClick:tap];
}
[self.titleScrollView addSubview:lable];
}
}
// 设置标题居中
- (void)setUpTitleCenter:(UILabel *)centerLabel
{
// 计算偏移量
CGFloat offsetX = centerLabel.center.x - XMGScreenW * 0.5;
if (offsetX < 0) offsetX = 0;
// 获取最大滚动范围
CGFloat maxOffsetX = self.titleScrollView.contentSize.width - XMGScreenW;
if (offsetX > maxOffsetX) offsetX = maxOffsetX;
// 滚动标题滚动条
[self.titleScrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
}
// 点击标题的时候就会调用
- (void)titleClick:(UITapGestureRecognizer *)tap
{
// NSLog(@"%s",__func__);
// NSLog(@"%@",tap.view);
// 0.获取选中的label
UILabel *selLabel = (UILabel *)tap.view;
// 1.标题颜色变成红色,设置高亮状态下的颜色
[self selectLabel:selLabel];
// 2.滚动到对应的位置
NSInteger index = selLabel.tag;
// 2.1 计算滚动的位置
CGFloat offsetX = index * XMGScreenW;
self.contentScrollView.contentOffset = CGPointMake(offsetX, 0);
// 3.给对应位置添加对应子控制器
[self showVc:index];
// 4.让选中的标题居中
[self setUpTitleCenter:selLabel];
}
// 显示控制器的view
- (void)showVc:(NSInteger)index
{
CGFloat offsetX = index * XMGScreenW;
UIViewController *vc = self.childViewControllers[index];
// NSLog(@"选中的view===%@===%@",vc.view,[vc.view class]);
// 判断控制器的view有没有加载过,如果已经加载过,就不需要加载
if (vc.isViewLoaded) return;
[self.contentScrollView addSubview:vc.view];
vc.view.frame = CGRectMake(offsetX, 0, XMGScreenW, XMGScreenH);
}
// 选中label
- (void)selectLabel:(UILabel *)label
{
// 取消高亮
_selLabel.highlighted = NO;
// 取消形变
_selLabel.transform = CGAffineTransformIdentity;
// 颜色恢复
_selLabel.textColor = [UIColor blackColor];
// 高亮
label.highlighted = YES;
// 形变
label.transform = CGAffineTransformMakeScale(radio, radio);
_selLabel = label;
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
// 计算滚动到哪一页
NSInteger index = scrollView.contentOffset.x / scrollView.bounds.size.width;
// 1.添加子控制器view
[self showVc:index];
// 2.把对应的标题选中
UILabel *selLabel = self.titleLabels[index];
[self selectLabel:selLabel];
// 3.让选中的标题居中
[self setUpTitleCenter:selLabel];
}
#pragma mark - UIScrollViewDelegate
// scrollView一滚动就会调用
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat curPage = scrollView.contentOffset.x / scrollView.bounds.size.width;
// 左边label角标
NSInteger leftIndex = curPage;
// 右边的label角标
NSInteger rightIndex = leftIndex + 1;
// 获取左边的label
UILabel *leftLabel = self.titleLabels[leftIndex];
// 获取右边的label
UILabel *rightLabel;
if (rightIndex < self.titleLabels.count - 1) {
rightLabel = self.titleLabels[rightIndex];
}
// 计算下右边缩放比例
CGFloat rightScale = curPage - leftIndex;
// NSLog(@"rightScale--%f",rightScale);
// 计算下左边缩放比例
CGFloat leftScale = 1 - rightScale;
// NSLog(@"leftScale--%f",leftScale);
// 0 ~ 1
// 1 ~ 2
// 左边缩放
leftLabel.transform = CGAffineTransformMakeScale(leftScale * 0.3 + 1, leftScale * 0.3+ 1);
// 右边缩放
rightLabel.transform = CGAffineTransformMakeScale(rightScale * 0.3 + 1, rightScale * 0.3+ 1);
// 设置文字颜色渐变
/*
R G B
黑色 0 0 0
红色 1 0 0
*/
leftLabel.textColor = [UIColor colorWithRed:leftScale green:0 blue:0 alpha:1];
rightLabel.textColor = [UIColor colorWithRed:rightScale green:0 blue:0 alpha:1];
// NSLog(@"%f",curPage);
}
#warning 1.添加所有子控制器对应标题
-(void)setUpChildViewControllers
{
OneVC *hotVC = [[OneVC alloc] init];
hotVC.title = @"热点";
[self addChildViewController:hotVC];
TwoVC *societyVC = [[TwoVC alloc] init];
societyVC.title = @"社会";
[self addChildViewController:societyVC];
ThreeVC *entertainmentVC = [[ThreeVC alloc] init];
entertainmentVC.title = @"娱乐";
[self addChildViewController:entertainmentVC];
FourVC *sportsVC = [[FourVC alloc] init];
sportsVC.title = @"体育";
[self addChildViewController:sportsVC];
FourVC *sportsVC1 = [[FourVC alloc] init];
sportsVC1.title = @"体育";
[self addChildViewController:sportsVC1];
FourVC *sportsVC2 = [[FourVC alloc] init];
sportsVC2.title = @"体育";
[self addChildViewController:sportsVC2];
}
类百思:
效果图:
代码:
#import "mainVC.h"
#import "OneVC.h"
#import "TwoVC.h"
#import "ThreeVC.h"
#import "FourVC.h"
@interface mainVC ()<UIScrollViewDelegate>
/** 顶部的所有标签 */
@property (nonatomic , weak) UIView *titlesView;
/** 标签栏底部的红色指示器 */
@property (nonatomic, weak) UIView *indicatorView;
/** 当前选中的按钮 */
@property (nonatomic, weak) UIButton *selectedButton;
/*底部的所有View*/
@property (nonatomic , strong) UIScrollView *contentView;
@end
@implementation mainVC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"百思";
//1.初始化子控制器
[self setUpChildViewControllers];
//2. 设置顶部的标签栏
[self setupTitlesView];
//3. 底部的scrollView
[self setupContentView];
}
-(void)setupTitlesView{
UIView *titlesView = [[UIView alloc] init];
titlesView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.7];
titlesView.width = self.view.width;
titlesView.height = 35;
titlesView.y = 64;
[self.view addSubview:titlesView];
self.titlesView = titlesView;
// 底部指示器
UIView *indicatorView = [[UIView alloc] init];
indicatorView.backgroundColor = [UIColor redColor];
indicatorView.height = 2;
indicatorView.y = titlesView.height - indicatorView.height;
self.indicatorView = indicatorView;
CGFloat width = titlesView.width /self.childViewControllers.count;
CGFloat height = titlesView.height;
for (NSInteger i = 0; i<self.childViewControllers.count; i++) {
UIButton *button = [[UIButton alloc] init];
button.height = height;
button.width = width;
button.x = i * width;
UIViewController *vc = self.childViewControllers[i];
[button setTitle:vc.title forState:UIControlStateNormal];
[button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[button setTitleColor:[UIColor blueColor] forState:UIControlStateDisabled];
button.titleLabel.font = [UIFont systemFontOfSize:16];
[button addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];
[titlesView addSubview:button];
button.tag = i;
// 默认点击了第一个按钮
if (i == 0) {
button.enabled = NO;
self.selectedButton = button;
// 让按钮内部的label根据文字内容来计算尺寸
[button.titleLabel sizeToFit];
self.indicatorView.width = button.titleLabel.width;
self.indicatorView.centerX = button.centerX;
}
}
[titlesView addSubview:indicatorView];
}
- (void)titleClick:(UIButton *)button
{
// 修改按钮状态
self.selectedButton.enabled = YES;
button.enabled = NO;
self.selectedButton = button;
// 动画
[UIView animateWithDuration:0.25 animations:^{
self.indicatorView.width = button.titleLabel.width;
self.indicatorView.centerX = button.centerX;
}];
//
//滚动
CGPoint offset = self.contentView.contentOffset;
offset.x = button.tag * self.contentView.width;
[self.contentView setContentOffset:offset animated:YES];
}
//初始化子控制器
-(void)setUpChildViewControllers
{
OneVC *hotVC = [[OneVC alloc] init];
hotVC.title = @"热点";
[self addChildViewController:hotVC];
TwoVC *societyVC = [[TwoVC alloc] init];
societyVC.title = @"社会";
[self addChildViewController:societyVC];
ThreeVC *entertainmentVC = [[ThreeVC alloc] init];
entertainmentVC.title = @"娱乐";
[self addChildViewController:entertainmentVC];
FourVC *sportsVC = [[FourVC alloc] init];
sportsVC.title = @"体育";
[self addChildViewController:sportsVC];
}
-(void)setupContentView
{
// 不要自动调整inset
self.automaticallyAdjustsScrollViewInsets = NO;
UIScrollView *contentView = [[UIScrollView alloc] init];
contentView.frame = self.view.bounds;
contentView.delegate = self;
contentView.pagingEnabled = YES;//设置分页
[self.view insertSubview:contentView atIndex:0];
//设置scrollerView的大小
contentView.contentSize = CGSizeMake(contentView.size.width * self.childViewControllers.count, 0);
self.contentView = contentView;
//添加第一个子控制器
[self scrollViewDidEndScrollingAnimation:contentView];
}
- (void)tagClick
{
NSLog(@"点击了");
}
#pragma mark - <UIScrollViewDelegate>
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
//滚动结束操作,添加自控制器的view
NSInteger index = scrollView.contentOffset.x /scrollView.width;
// UITableViewController *vc = self.childViewControllers[index];
UIViewController *vc = self.childViewControllers[index];
vc.view.x = scrollView.contentOffset.x;
vc.view.y = 0;//设置控制器view的y值为0(默认是20)
vc.view.height = scrollView.height;// 设置控制器view的height值为整个屏幕的高度(默认是比屏幕高度少个20)
[scrollView addSubview:vc.view];
}
//滑动之后结束
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self scrollViewDidEndScrollingAnimation:scrollView];
//点击按钮
NSInteger index = scrollView.contentOffset.x /scrollView.width;
[self titleClick:self.titlesView.subviews[index]];
NSLog(@"titileView的个数------%lu",(unsigned long)self.titlesView.subviews.count);
}
@end
二、父子控制器:
利用父子控制器来进行视图的切换。
效果:
代码:
#import "ViewController.h"
#import <Foundation/Foundation.h>
#import "SocietyViewController.h"
#import "TopLineViewController.h"
#import "HotViewController.h"
/*
多控制器:当有很多控制器,交给一个大控制器管理
父子控制器:导航控制器,UITabBarControler
父子控制器本质:搞一个控制器容器,管理很多子控制器.
模仿UITabBarControler,写一个自己的UITabBarControler,条在上面.
任何控制器都可以是一个容器控制器.因为任何控制器都可以调用addChildViewController
*/
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *societyBtn;
@property (weak, nonatomic) IBOutlet UIButton *topLineBtn;
@property (weak, nonatomic) IBOutlet UIButton *hotBtn;
@property (nonatomic, strong) SocietyViewController *societyVc;
@property (nonatomic, strong) TopLineViewController *topLineVc;
@property (nonatomic, strong) HotViewController *hotVc;
@end
@implementation ViewController
// 父子控制器:如果一个控制器的view显示,那么这个控制器必须存在
// 显示社会界面
- (IBAction)showSociety:(id)sender {
// 1.创建控制器
if (_societyVc == nil) {
SocietyViewController *society = [[SocietyViewController alloc] init];
_societyVc = society;
}
[self.view addSubview:_societyVc.view];
// 移除其他控制器的view
[_topLineVc.view removeFromSuperview];
[_hotVc.view removeFromSuperview];
// 控制器的view在,控制器被销毁.
// 控制器不存在,控制器的view也是可以存在
// 当控制器view存在,控制器不存在,会导致控制器view上面的所有事件都不能处理
// ARC管理原则:只要一个对象没有被强引用,就会被销毁
}
// 显示头条
- (IBAction)showTopLine:(id)sender {
if (_topLineVc == nil) {
TopLineViewController *topLine = [[TopLineViewController alloc] init];
_topLineVc = topLine;
}
[self.view addSubview:_topLineVc.view];
// 移除其他控制器的view
[_societyVc.view removeFromSuperview];
[_hotVc.view removeFromSuperview];
}
// 显示热点
- (IBAction)showHot:(id)sender {
if (_hotVc == nil) {
HotViewController *hot = [[HotViewController alloc] init];
_hotVc = hot;
}
[self.view addSubview:_hotVc.view];
// 移除其他控制器的view
[_societyVc.view removeFromSuperview];
[_topLineVc.view removeFromSuperview];
}
/*
存放问题:
1.每次都需要创建控制器
2.每次都会添加界面,只是想显示当前显示view,其他view移除
3.每次控制器都会销毁,就不能处理控制器view上面的事件
*/
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 设置按钮标题
[_societyBtn setTitle:@"社会" forState:UIControlStateNormal];
[_topLineBtn setTitle:@"头条" forState:UIControlStateNormal];
[_hotBtn setTitle:@"热点" forState:UIControlStateNormal];
}
利用autoLayout来进行三平分视图:
思路:
1、底部设置一个view,设置限制
2、拖3个button放在view上
3、设置第一个button的contains为:左:0 上:0 右:0 下:0
4、设置第二个button的contains为:上:0 右:0 与第一个button等宽等高
5、设置第三个button的contains为:上:0 右:0 与第二个button等宽等高