实战项目-网易

重点:ContentOffset偏移量计算

判断防止View视图重复加载

 UIViewController * vc = self.childViewControllers[i];
    //FIXME:防止重复加载View视图
    if (vc.viewIfLoaded) {
        //iOS 9.0之后
        return;
    }
    //FIXME:通用
    if (vc.view.superview) {
        return;
    }

 

代码:(未抽取)

#import "ViewController.h"
#import "TopLineViewController.h"
#import "HotViewController.h"
#import "VideoViewController.h"
#import "ScienceViewController.h"
#import "SocietyViewController.h"
#import "ReaderViewController.h"
#define ScreenW [[UIScreen mainScreen] bounds].size.width
#define ScreenH [[UIScreen mainScreen] bounds].size.height
@interface ViewController ()<UIScrollViewDelegate>
/** 标题按钮数组 */
@property (nonatomic, strong) NSMutableArray * titleBtns ;
/** 上一次选中的按钮 */
@property (nonatomic, strong) UIButton * selectedBtn ;
@property (nonatomic, weak) UIScrollView *titleScrollView;
@property (nonatomic, weak) UIScrollView *contentScrollView;

@end

@implementation ViewController
-(NSMutableArray *)titleBtns {
    if (!_titleBtns) {
        _titleBtns = @[].mutableCopy;
    }
    return _titleBtns;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navigationItem.title = @"网易新闻";
    
    // 1.添加标题滚动视图
    [self setupTitleScrollView];
    
    // 2.添加内容滚动视图
    [self setupContentScrollView];
    
    //3.添加所有的子控制器
    [self setupAllChildViewController];
    
    //4.设置所有的标题
    [self setupAllTitles];
    
    //5.处理标题的点击
    
    //7.FIXME:scrollView的额外滚动区域64
    //iOS 7以后,导航控制器中scrollView顶部会添加64的额外滚动区域
    self.automaticallyAdjustsScrollViewInsets = NO;
    
}
#pragma mark - 设置所有的标题
- (void)setupAllTitles {
    //已经把我们想要的内容展示上去 -> 展示的效果是否是我们想要的(调整细节)
    //1.标题的颜色 为黑色
    //2.需要让titleScrollView可以滚动
    //添加所有标题按钮
    NSInteger count = self.childViewControllers.count;
    CGFloat btnW = 100;
    CGFloat btnH = self.titleScrollView.bounds.size.height;
    CGFloat btnX = 0;
    for (NSInteger i = 0; i<count; i++) {
        UIButton *titleBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        titleBtn.tag = i;
        //设置标题
        UIViewController * vc = self.childViewControllers[i];
        [titleBtn setTitle:vc.title forState:UIControlStateNormal];
        //设置Frame
        btnX = i * btnW;
        titleBtn.frame = CGRectMake(btnX, 0, btnW, btnH);
        [titleBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        //监听按钮点击
        [titleBtn addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];
        //设置第一个按钮默认选中(头条默认选中)
        if (i == 0) {
            [self titleClick:titleBtn];
        }
        //把标题按钮保存到对应的数组中
        [self.titleBtns addObject:titleBtn];
        [self.titleScrollView addSubview:titleBtn];
    }
    
    //设置标题滚动范围
    self.titleScrollView.contentSize = CGSizeMake(count * btnW, 0);
    self.titleScrollView.showsHorizontalScrollIndicator = NO;
    
    //6.设置内容的滚动范围
    self.contentScrollView.contentSize = CGSizeMake(count * ScreenW, 0);
    //bug:代码跟我的一样,但是标题显示不出来
    //bug: 内容往下移动,莫名其妙
    //FIXME:9.选中标题居中处理->选中标题
    //10.标题文字缩放
}

#pragma mark - 选中标题
- (void)selButton:(UIButton*)button {
    _selectedBtn.transform = CGAffineTransformIdentity;
    [_selectedBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    //_selectedBtn = button;
    //标题居中处理
    [self setupTitleCenter:button];
    //字体缩放: 形变
    button.transform = CGAffineTransformMakeScale(1.3, 1.3);
    _selectedBtn = button;
    [self setupTitleScale];
}
#pragma mark - 字体缩放
- (void)setupTitleScale {
    
}
#pragma mark - 标题居中处理
- (void)setupTitleCenter:(UIButton*)button {
    //本质:修改titleScrollView的偏移量
    CGFloat offsetX = button.center.x - ScreenW * 0.5;
    NSLog(@"offsetX==%f",offsetX);
    //头条、热点(offsetX<0)
    if (offsetX < 0) {
        offsetX = 0;
    }
    //最大偏移量计算(解决订阅和科技)
     CGFloat maxOffsetX = self.titleScrollView.contentSize.width - ScreenW;
    if (offsetX > maxOffsetX) {
        offsetX = maxOffsetX;
    }
    [self.titleScrollView setContentOffset: CGPointMake(offsetX, 0) animated:YES];
    //此时有bug:点击每个按钮都居中了,例如:头条、热点(offsetX<0)
}

#pragma mark - 添加一个子控制器的View
- (void)setupOneViewController:(NSInteger)i {
    UIViewController * vc = self.childViewControllers[i];
    //FIXME:防止重复加载View视图
//    if (vc.viewIfLoaded) {
//        //iOS 9.0之后
//        return;
//    }
    //FIXME:通用
    if (vc.view.superview) {
        return;
    }
    CGFloat x = i * ScreenW;
    vc.view.frame = CGRectMake(x, 0, ScreenW, self.contentScrollView.bounds.size.height);
    [self.contentScrollView addSubview:vc.view];
}
#pragma mark - 处理标题点击
- (void)titleClick:(UIButton*)button {
    //FIXME:8.监听内容视图滚动
    NSInteger i = button.tag;
    //1.标题颜色变为红色
    [self selButton:button];
    //2.把对应子控制器的View添加上去
    [self setupOneViewController:i];
    //3.滚动到对应的位置
    self.contentScrollView.contentOffset = CGPointMake(i * ScreenW, 0);
}
#pragma mark - 添加所有子控制器
- (void)setupAllChildViewController {
    
    //头条
    TopLineViewController * vc = [TopLineViewController new];
    vc.title = @"头条";
    [self addChildViewController:vc];
    //热点
    HotViewController * hotVC = [HotViewController new];
    hotVC.title = @"热点";
    [self addChildViewController:hotVC];
    //视频
    VideoViewController * videoVC = [VideoViewController new];
    videoVC.title = @"视频";
    [self addChildViewController:videoVC];
    //社会
    SocietyViewController * societyVC = [SocietyViewController new];
    societyVC.title = @"社会";
    [self addChildViewController:societyVC];
    //订阅
    ReaderViewController * readerVC = [ReaderViewController new];
    readerVC.title = @"订阅";
    [self addChildViewController:readerVC];
    //科技
    ScienceViewController * scienceVC = [ScienceViewController new];
    scienceVC.title = @"科技";
    [self addChildViewController:scienceVC];
    
}
#pragma mark - 添加标题滚动视图
- (void)setupTitleScrollView
{
    // 创建titleScrollView
    UIScrollView *titleScrollView = [[UIScrollView alloc] init];
    //titleScrollView.backgroundColor = [UIColor redColor];
    CGFloat y = self.navigationController.navigationBarHidden ? 20 : 64;
    titleScrollView.frame = CGRectMake(0, y, self.view.bounds.size.width, 44);
    [self.view addSubview:titleScrollView];
    _titleScrollView = titleScrollView;
    
}

#pragma mark - 添加内容滚动视图
- (void)setupContentScrollView
{
    // 创建contentScrollView
    UIScrollView *contentScrollView = [[UIScrollView alloc] init];
    contentScrollView.backgroundColor = [UIColor greenColor];
    CGFloat y = CGRectGetMaxY(self.titleScrollView.frame);
    contentScrollView.frame = CGRectMake(0, y, self.view.bounds.size.width, self.view.bounds.size.height - y);
    [self.view addSubview:contentScrollView];
    _contentScrollView = contentScrollView;
    //设置contentScrollView的属性
    // 分页
    self.contentScrollView.pagingEnabled = YES;
    // 弹簧
    self.contentScrollView.bounces = NO;
    // 指示器
    self.contentScrollView.showsHorizontalScrollIndicator = NO;
    //设置代理.目的:监听内容滚动视图 什么时候滚动完成
    self.contentScrollView.delegate = self;
    
}
#pragma mark - UIScrollViewDelegate
#pragma mark - 滚动完成的时候调用
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    
    //获取当前的角标
    NSInteger i =  scrollView.contentOffset.x / ScreenW;//偏移量/屏幕宽度
    
    //获取标题按钮
    UIButton *titleBtn = self.titleBtns[i];
    
    //1.选中标题
    [self selButton:titleBtn];
    //2.把对应子控制器的view添加上去
    [self setupOneViewController:i];
    
}
#pragma mark - 只要一滚动就需要字体渐变
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    //字体缩放  1.缩放比例 2.缩放哪两个按钮
    NSInteger page = scrollView.contentOffset.x / ScreenW;
    NSLog(@"%ld",page);
    NSInteger leftI = scrollView.contentOffset.x / ScreenW;
    NSInteger rightI = leftI + 1;
    // 获取左边的按钮
    UIButton * leftBtn = self.titleBtns[leftI];
    NSInteger count = self.titleBtns.count;
    
    // 获取右边的按钮
    UIButton * rightBtn;
    if (rightI < count) {
        rightBtn = self.titleBtns[rightI];
    }
    // 0~1 => 1~1.3
    CGFloat scaleR = scrollView.contentOffset.x / ScreenW;
    scaleR -= leftI;
    
    CGFloat scaleL = 1- scaleR;
    NSLog(@"%f",scaleR);
    //缩放按钮
    leftBtn.transform = CGAffineTransformMakeScale(scaleL * 0.3+1, scaleL * 0.3+1);
    rightBtn.transform = CGAffineTransformMakeScale(scaleR * 0.3+1, scaleR * 0.3+1);
    
    //FIXME:颜色渐变
    //黑色变成红色
    UIColor * rightColor = [UIColor colorWithRed:scaleR green:0 blue:0 alpha:1];
    UIColor * leftColor = [UIColor colorWithRed:scaleL green:0 blue:0 alpha:1];
    [rightBtn setTitleColor:rightColor forState:UIControlStateNormal];
    [leftBtn setTitleColor:leftColor forState:UIControlStateNormal];
    
}
/*
 颜色:3种颜色通道组成: R:红 G 绿 B: k蓝
 白色: 1 1 1
 黑色: 0 0 0
 红色: 1 0 0
 */

 代码:(已抽取)

BaseVC:

#import "ViewController.h"
#define ScreenW [[UIScreen mainScreen] bounds].size.width
#define ScreenH [[UIScreen mainScreen] bounds].size.height
@interface ViewController ()<UIScrollViewDelegate>
/** 标题按钮数组 */
@property (nonatomic, strong) NSMutableArray * titleBtns ;
/** 上一次选中的按钮 */
@property (nonatomic, strong) UIButton * selectedBtn ;
@property (nonatomic, weak) UIScrollView *titleScrollView;
@property (nonatomic, weak) UIScrollView *contentScrollView;
/** 判断是否初始化 */
@property (nonatomic, assign) BOOL isInitialize;
@end

@implementation ViewController
-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    if (_isInitialize == NO) {
        //4.设置所有的标题
        [self setupAllTitles];
        _isInitialize = YES;
    }
}
-(NSMutableArray *)titleBtns {
    if (!_titleBtns) {
        _titleBtns = @[].mutableCopy;
    }
    return _titleBtns;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationItem.title = @"网易新闻";
    // 1.添加标题滚动视图
    [self setupTitleScrollView];
    
    // 2.添加内容滚动视图
    [self setupContentScrollView];
    //5.处理标题的点击
    
    //7.FIXME:scrollView的额外滚动区域64
    //iOS 7以后,导航控制器中scrollView顶部会添加64的额外滚动区域
    self.automaticallyAdjustsScrollViewInsets = NO;
}
#pragma mark - 设置所有的标题
- (void)setupAllTitles {
    //已经把我们想要的内容展示上去 -> 展示的效果是否是我们想要的(调整细节)
    //1.标题的颜色 为黑色
    //2.需要让titleScrollView可以滚动
    //添加所有标题按钮
    NSInteger count = self.childViewControllers.count;
    CGFloat btnW = 100;
    CGFloat btnH = self.titleScrollView.bounds.size.height;
    CGFloat btnX = 0;
    for (NSInteger i = 0; i<count; i++) {
        UIButton *titleBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        titleBtn.tag = i;
        //设置标题
        UIViewController * vc = self.childViewControllers[i];
        [titleBtn setTitle:vc.title forState:UIControlStateNormal];
        //设置Frame
        btnX = i * btnW;
        titleBtn.frame = CGRectMake(btnX, 0, btnW, btnH);
        [titleBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        //监听按钮点击
        [titleBtn addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];
        //设置第一个按钮默认选中(头条默认选中)
        if (i == 0) {
            [self titleClick:titleBtn];
        }
        //把标题按钮保存到对应的数组中
        [self.titleBtns addObject:titleBtn];
        [self.titleScrollView addSubview:titleBtn];
    }
    //设置标题滚动范围
    self.titleScrollView.contentSize = CGSizeMake(count * btnW, 0);
    self.titleScrollView.showsHorizontalScrollIndicator = NO;
    //6.设置内容的滚动范围
    self.contentScrollView.contentSize = CGSizeMake(count * ScreenW, 0);
}

#pragma mark - 选中标题
- (void)selButton:(UIButton*)button {
    _selectedBtn.transform = CGAffineTransformIdentity;
    [_selectedBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    //_selectedBtn = button;
    //标题居中处理
    [self setupTitleCenter:button];
    //字体缩放: 形变
    button.transform = CGAffineTransformMakeScale(1.3, 1.3);
    _selectedBtn = button;
    [self setupTitleScale];
}
#pragma mark - 字体缩放
- (void)setupTitleScale {
    
}
#pragma mark - 标题居中处理
- (void)setupTitleCenter:(UIButton*)button {
    //本质:修改titleScrollView的偏移量
    CGFloat offsetX = button.center.x - ScreenW * 0.5;
    NSLog(@"offsetX==%f",offsetX);
    //头条、热点(offsetX<0)
    if (offsetX < 0) {
        offsetX = 0;
    }
    //最大偏移量计算(解决订阅和科技)
     CGFloat maxOffsetX = self.titleScrollView.contentSize.width - ScreenW;
    if (offsetX > maxOffsetX) {
        offsetX = maxOffsetX;
    }
    [self.titleScrollView setContentOffset: CGPointMake(offsetX, 0) animated:YES];
    //此时有bug:点击每个按钮都居中了,例如:头条、热点(offsetX<0)
}

#pragma mark - 添加一个子控制器的View
- (void)setupOneViewController:(NSInteger)i {
    UIViewController * vc = self.childViewControllers[i];
    //FIXME:防止重复加载View视图
//    if (vc.viewIfLoaded) {
//        //iOS 9.0之后
//        return;
//    }
    //FIXME:通用
    if (vc.view.superview) {
        return;
    }
    CGFloat x = i * ScreenW;
    vc.view.frame = CGRectMake(x, 0, ScreenW, self.contentScrollView.bounds.size.height);
    [self.contentScrollView addSubview:vc.view];
}
#pragma mark - 处理标题点击
- (void)titleClick:(UIButton*)button {
    //FIXME:8.监听内容视图滚动
    NSInteger i = button.tag;
    //1.标题颜色变为红色
    [self selButton:button];
    //2.把对应子控制器的View添加上去
    [self setupOneViewController:i];
    //3.滚动到对应的位置
    self.contentScrollView.contentOffset = CGPointMake(i * ScreenW, 0);
}
#pragma mark - 添加标题滚动视图
- (void)setupTitleScrollView
{
    // 创建titleScrollView
    UIScrollView *titleScrollView = [[UIScrollView alloc] init];
    //titleScrollView.backgroundColor = [UIColor redColor];
    CGFloat y = self.navigationController.navigationBarHidden ? 20 : 64;
    titleScrollView.frame = CGRectMake(0, y, self.view.bounds.size.width, 44);
    [self.view addSubview:titleScrollView];
    _titleScrollView = titleScrollView;
    
}

#pragma mark - 添加内容滚动视图
- (void)setupContentScrollView
{
    // 创建contentScrollView
    UIScrollView *contentScrollView = [[UIScrollView alloc] init];
    contentScrollView.backgroundColor = [UIColor greenColor];
    CGFloat y = CGRectGetMaxY(self.titleScrollView.frame);
    contentScrollView.frame = CGRectMake(0, y, self.view.bounds.size.width, self.view.bounds.size.height - y);
    [self.view addSubview:contentScrollView];
    _contentScrollView = contentScrollView;
    //设置contentScrollView的属性
    // 分页
    self.contentScrollView.pagingEnabled = YES;
    // 弹簧
    self.contentScrollView.bounces = NO;
    // 指示器
    self.contentScrollView.showsHorizontalScrollIndicator = NO;
    //设置代理.目的:监听内容滚动视图 什么时候滚动完成
    self.contentScrollView.delegate = self;
    
}
#pragma mark - UIScrollViewDelegate
#pragma mark - 滚动完成的时候调用
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    
    //获取当前的角标
    NSInteger i =  scrollView.contentOffset.x / ScreenW;//偏移量/屏幕宽度
    
    //获取标题按钮
    UIButton *titleBtn = self.titleBtns[i];
    
    //1.选中标题
    [self selButton:titleBtn];
    //2.把对应子控制器的view添加上去
    [self setupOneViewController:i];
    
}
#pragma mark - 只要一滚动就需要字体渐变
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    //字体缩放  1.缩放比例 2.缩放哪两个按钮
    NSInteger page = scrollView.contentOffset.x / ScreenW;
    NSLog(@"%ld",page);
    NSInteger leftI = scrollView.contentOffset.x / ScreenW;
    NSInteger rightI = leftI + 1;
    // 获取左边的按钮
    UIButton * leftBtn = self.titleBtns[leftI];
    NSInteger count = self.titleBtns.count;
    
    // 获取右边的按钮
    UIButton * rightBtn;
    if (rightI < count) {
        rightBtn = self.titleBtns[rightI];
    }
    // 0~1 => 1~1.3
    CGFloat scaleR = scrollView.contentOffset.x / ScreenW;
    scaleR -= leftI;
    
    CGFloat scaleL = 1- scaleR;
    NSLog(@"%f",scaleR);
    //缩放按钮
    leftBtn.transform = CGAffineTransformMakeScale(scaleL * 0.3+1, scaleL * 0.3+1);
    rightBtn.transform = CGAffineTransformMakeScale(scaleR * 0.3+1, scaleR * 0.3+1);
    
    //FIXME:颜色渐变
    //黑色变成红色
    UIColor * rightColor = [UIColor colorWithRed:scaleR green:0 blue:0 alpha:1];
    UIColor * leftColor = [UIColor colorWithRed:scaleL green:0 blue:0 alpha:1];
    [rightBtn setTitleColor:rightColor forState:UIControlStateNormal];
    [leftBtn setTitleColor:leftColor forState:UIControlStateNormal];
    
}

网易VC

#import <UIKit/UIKit.h>
#import "ViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface HKWYViewController : ViewController
@end
NS_ASSUME_NONNULL_END

#import "HKWYViewController.h"
#import "TopLineViewController.h"
#import "HotViewController.h"
#import "VideoViewController.h"
#import "ScienceViewController.h"
#import "SocietyViewController.h"
#import "ReaderViewController.h"
@interface HKWYViewController ()

@end

@implementation HKWYViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //3.添加所有的子控制器
    [self setupAllChildViewController];
    
}
#pragma mark - 添加所有子控制器
- (void)setupAllChildViewController {
    
    //头条
    TopLineViewController * vc = [TopLineViewController new];
    vc.title = @"头条";
    [self addChildViewController:vc];
    //热点
    HotViewController * hotVC = [HotViewController new];
    hotVC.title = @"热点";
    [self addChildViewController:hotVC];
    //视频
    VideoViewController * videoVC = [VideoViewController new];
    videoVC.title = @"视频";
    [self addChildViewController:videoVC];
    //社会
    SocietyViewController * societyVC = [SocietyViewController new];
    societyVC.title = @"社会";
    [self addChildViewController:societyVC];
    //订阅
    ReaderViewController * readerVC = [ReaderViewController new];
    readerVC.title = @"订阅";
    [self addChildViewController:readerVC];
    //科技
    ScienceViewController * scienceVC = [ScienceViewController new];
    scienceVC.title = @"科技";
    [self addChildViewController:scienceVC];
    
}

 

posted @ 2018-11-29 12:53  淡然微笑_Steven  阅读(227)  评论(0编辑  收藏  举报