• 实战项目-网易


    重点: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];
        
    }
  • 相关阅读:
    xuexi
    太厉害了!腾讯T4大牛把《数据结构与算法》讲透了,带源码笔记
    python 死循环
    redis 锁
    Opencv4.1.0交叉编译----终端摄像头内算法嵌入,海思HISI、雄迈ARM编译链使用经验
    SpringCloud之FeignClient调用跨微服接口
    Elasticsearch父子级查询及祖孙辈parent/child关联查询
    服务器ip地址与域名解析及http转https
    RestTemplate请求第三方接口添加Headers token及设置请求体
    kanzi 一些基础参数变量
  • 原文地址:https://www.cnblogs.com/StevenHuSir/p/10037622.html
Copyright © 2020-2023  润新知