最近項目中用到了模仿網易新聞的標題欄,盡管現在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等寬等高