仿网易的标题栏 - iOS

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


仿网易的标题栏 - iOS_第1张图片
网易.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 ()

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

类百思:
效果图:


仿网易的标题栏 - iOS_第2张图片
百思.gif

代码:

#import "mainVC.h"

#import "OneVC.h"
#import "TwoVC.h"
#import "ThreeVC.h"
#import "FourVC.h"


@interface mainVC ()

/** 顶部的所有标签 */
@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
-(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

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

仿网易的标题栏 - iOS_第3张图片
父子控制器.gif

代码:

#import "ViewController.h"

#import 

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

仿网易的标题栏 - iOS_第4张图片
三等分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等宽等高

你可能感兴趣的:(仿网易的标题栏 - iOS)