仿网易的标题栏 - iOS

最近项目中用到了模仿网易新闻的标题栏,尽管现在gitHub和code4app上有好多第三方,但是还是想搞清楚是怎么实现的,特此记录。有可以滚动和不可以滚动的。
一 、模仿网易:
效果:


网易.gif

代码:

#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];
    
}

类百思:
效果图:


百思.gif

代码:

#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

二、父子控制器:
利用父子控制器来进行视图的切换。
效果:

父子控制器.gif

代码:

#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来进行三平分视图:

三等分view.gif

思路:
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等宽等高

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容