仿網易的標題欄 - 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閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容