• 精度解析百思不得姐流行框架之精华版


    0 框架效果图

    这里写图片描写叙述

    一 解说顺序

    1 标题部分

    2 内容显示部分

    3 完好代码

    4 知识补充

    二 内容显示部分解析

    1 搭建: 通过观察该部分执行情况,支持上下滑动,同一时候也支持左右滑动

    —-> 1.1 结论: 父控件採用UIScrollView;子控件採用五个tableView

    2 分析一: 考虑内容显示的数据量比較大

    —-> 2.1 做法: tableView採用循环利用

    3 tableView的排列顺序: 设置scrollerView的偏移量为5个tableView的宽度(contentSize),将tableView依次从屏幕向右排列

    4 观察:父控件scrollerView不能上下滑动,设置上下滑动的contentSize为0

    5 各部分的分工情况: scrollerView:负责左右滚动; tableView:负责上下滚动

    6 scrollerView的frame决定可视范围;scrollerView的contentSize决定滑动范围

    三 标题栏显示部分解析

    1 观察:标题栏并不能滑动

    —-> 1.1 结论:能够通过UIView来实现

    2 点击的标题可选方案: 1> button 2> Label

    3 终于方案:选择button

    4 选中后显示的下划线:採取用一个UIView来实现

    四 标题栏相关说明和代码

    1 通过观察,能够通过标题栏看究竟部的内容,说明标题栏是有透明度的,须要特别设置

    2 设置标题的透明度(四种方法:三种可取,一种不可取)

    —-> 2.1 方法一 :—->可取
    titleView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];
    —-> 2.2 方法二:—->可取
    titleView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.5];
    —-> 2.3 方法三: —->可取
    titleView.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.5];
    —-> 2.4 方法四:—->不可取
    —-> 不可取原因:内部的子控件也会变透明
    titleView.alpha = 0.3;

    3 加入标题栏的代码

    #pragma mark - 加入标题栏
    - (void)setUpTitlesView
    {
        //创建UIView对象
        UIView *titleView = [[UIView alloc] init];
        //设置背景色的透明度(方法一)-->可取
        titleView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];
        //设置尺寸
        titleView.frame = CGRectMake(0, XFJ_navBar, XFJ_screenW, 35);
        //加入到view中
        [self.view addSubview:titleView];
        //赋值
        self.titleView = titleView;
        //调用加入button的方法
        [self setUptitlesButton];
    
        //button的标题下划线
        [self setUpTitlesUnderLine];
    }

    五 加入标题栏中的button

    1 採取for循环的方式创建

    2 内部写入对button的监听方法

    3 创建的button为自己定义button

    4 有关点击后button的状态设置

    —> 加入button的代码:
    #pragma mark - 加入标题中的button
    - (void)setUptitlesButton
    {
        //包装数组
        NSArray *titles = @[@"全部",@"视频",@"声音",@"图片",@"段子"];
        //取出数组里面的标题总数
        NSInteger count = titles.count;
        CGFloat titleButtonX = 0;
        CGFloat titleButtonY = 0;
        //设置button的宽度
        CGFloat titleButtonW = self.titleView.XFJ_Width / count;
        //button的高度
        CGFloat titleButtonH = self.titleView.XFJ_Height;
        for (NSInteger i = 0; i < count; i++) {
            //创建button
            XFJTitleButton *titleButtons = [[XFJTitleButton alloc] init];
            titleButtonX = i * titleButtonW;
            //给button绑定tag
            titleButtons.tag = i;
            //设置尺寸
            titleButtons.frame = CGRectMake(titleButtonX, titleButtonY, titleButtonW, titleButtonH);
            //给button加入标题
            [titleButtons setTitle:titles[i] forState:UIControlStateNormal];
            //监听button的点击
            [titleButtons addTarget:self action:@selector(titleButtonClick:) forControlEvents:UIControlEventTouchUpInside];
            //加入button
            [self.titleView addSubview:titleButtons];
        }
    }

    六 button监听

    1 button颜色的变化(三种方法:一种通过改变颜色;二种通过改变button的状态)

    —> 1.1 直接通过改变颜色(传统的做法)
    #pragma mark - 实现监听中的方法
    - (void)titleButtonClick:(UIButton *)button
    {
        //让上一个button的状态为黑色
        [self.previousButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        //让当前的button为红色
        [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
        //将当前button的颜色状态给上一个button
        self.previousButton = button;
    —> 1.2 传统方法的局限性:不方便改动文字的颜色
    —> 1.3 方法一假设须要改动,就取决于设置的颜色
    [titleButtons setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
    [titleButtons setTitleColor:[UIColor redColor] forState:UIControlStateSelected];

    2 直接通过改变button的状态来改变button的颜色

    —> 2.1 局限性:button的颜色能改变,可是再次点击button的时候,button不能接受事件.
    —> 2.2 button设置的状态代码
    [titleButtons setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
    [titleButtons setTitleColor:[UIColor redColor] forState:UIControlStateDisabled];

    2.3 button实现代码:(按照公司需求而定)

    //让上一个button的状态为灰色
        self.previousButton.enabled = YES;
        //让当前button为红色
        button.enabled = NO;
        //将当前button的颜色状态给上一个button
        self.previousButton = button;

    七 button下划线的相关设置

    1 下划线随着button的切换而变化

    2 该功能抽成一个方法,调用位置—>创建标题栏方法中调用

    —> 代码:
    #pragma mark - 加入标题button的选中线
    - (void)setUpTitlesUnderLine
    {
        //取出button
        XFJTitleButton *firstTitleButton = self.titleView.subviews.firstObject;
        //创建下划线的view
        UIView *underViewLine = [[UIView alloc] init];
        CGFloat underViewLineX = 0;
        CGFloat underViewLineH = 1;
        CGFloat underViewLineY = self.titleView.XFJ_Height - underViewLine.XFJ_Height;
        CGFloat underViewLineW = 0;
        //尺寸
        underViewLine.frame = CGRectMake(underViewLineX, underViewLineY, underViewLineW, underViewLineH);
        //下划线的颜色状态和第一个button一样
        underViewLine.backgroundColor = [firstTitleButton titleColorForState:UIControlStateSelected];
        //将button加入到标题中
        [self.titleView addSubview:underViewLine];
        //设置第一个button的状态
        firstTitleButton.selected = YES;
        //让第一个button的状态成为上一个button状态
        self.previousButton = firstTitleButton;
        //设置下划线的大小自适应
        [firstTitleButton.titleLabel sizeToFit];
        //赋值
        self.underViewLine = underViewLine;
        //设置线的宽度
        self.underViewLine.XFJ_Width = firstTitleButton.titleLabel.XFJ_Width + 10;
        //设置线的中心点和button对齐
        self.underViewLine.XFJ_centerX = firstTitleButton.XFJ_centerX;
    }

    3 注意点一:必须要先设置先的宽度,才干设置线的中心点对齐方式,否则会出现启动app的时候button的下划线会有一段动画效果.

    4 注意点二:让第一个button成为选中状态千万不能省,省了的话也会有莫名其妙的错误

    5 点击button,下划线移动到相应的button下,代码书写位置:实现对button点击的监听方法中

    //点击button移动下划线
        [UIView animateWithDuration:0.25 animations:^{
    
            //设置线的宽度
            self.underViewLine.XFJ_Width = button.titleLabel.XFJ_Width + 10;
            //设置线的中心点和button对齐
            self.underViewLine.XFJ_centerX = button.XFJ_centerX;

    八 内容scrollerView相关设置

    1 重点:关闭自己主动调节内边距

    —> 1.1 原因:当有子控件加入到UIScrollView中时,子控件顶部的间距会默认往下移动64的间距(仅仅针对UIScrollView中的子控件)

    2 关闭UIScrollView的点击顶部状态栏,tableView内容回到顶部(为后面状态栏设置埋伏笔)

    3 设置contenSize,否则tableView将无法滚动

    4 优化代码部分(后面补上)

    5 整体代码部分:

    #pragma mark - 加入内容的scrollerView
    - (void)setUpAllChindView
    {
        //不要调整scrollerView的内边距
        self.automaticallyAdjustsScrollViewInsets = NO;
        //创建scrollerView
        UIScrollView *contentView = [[UIScrollView alloc] init];
        contentView.frame = self.view.bounds;
        //这个scrollerView不须要回到顶部
        contentView.scrollsToTop = NO;
        //加入到内容的view中
        [self.view addSubview:contentView];
    
        //加入子控制器的view到scrollerView中
        //取出控制器的数量
        NSInteger count = self.childViewControllers.count;
        for (NSInteger i = 0; i < count; i++) {
            //依据相应的i值取出控制器的view(该行代码是照成一次性创建全部tableview的原因)
            UIView *childView = self.childViewControllers[i].view;
            //设置尺寸
            childView.frame = CGRectMake(i * XFJ_screenW, 0, XFJ_screenW, XFJ_screenH);
    
            //加入view到scrollerView中
            [contentView addSubview:childView];
        }
        //开启分页
        contentView.pagingEnabled = YES;
        //设置代理
        contentView.delegate = self;
        //设置滚动范围
        contentView.contentSize = CGSizeMake(count * XFJ_screenW, 0);
        //隐藏滚动栏
        contentView.showsHorizontalScrollIndicator = NO;
        contentView.showsVerticalScrollIndicator = NO;
        //赋值
        self.contentView = contentView;
    }

    九 标题与相应的tableView联动(一)

    1 联动:开发中专业术语.意思是:通过改变一方某个状态,另外一方也会跟着改变

    2 点击标题栏中的button,切换相应的控制器的view

    3 代码书写位置

    –> 1 由于是点击button切换相应的控制器,那么代码书写的位置肯定是在button监听实现部分,而且移动的时候也须要动画

    —-> 2 联动三种方法:

    —-> 2.1 通过在创建button的时候给button绑定tag(方法一)—>(第五部分tag已经加入)
    //标题和子控制器view的联动问题(第一种方法)
            self.contentView.contentOffset = CGPointMake(button.tag * XFJ_screenW, self.contentView.bounds.origin.y);
                2.2 通过绑定的tag改动UIScrollView的偏移量(方法二)
    //标题和子控制器view的联动问题(另外一种方法)-->直接改动偏移量
            CGPoint offset = self.contentView.contentOffset;
            offset.x = button.tag * XFJ_screenW;
            self.contentView.contentOffset = offset;
           2.3 通过遍历标题栏的子控件(方法三:相对于上面2种比較好性能,可是假设button比較少,这方面问题也是不存在的)
    //通过遍历的方法(方法三:相对于上面比較耗性能)--->遍历
            NSInteger index = [self.titleView.subviews indexOfObject:button];
            self.contentView.contentOffset = CGPointMake(index * XFJ_screenW,
                                                         self.contentView.bounds.origin.y);

    十 tableView与相应的标题联动(二)

    1 实现方案:直接通过代理就能够实现

    2 思路: 通过偏移量和屏幕宽度的计算得到tableView的索引

    3 加入内容UIScrollView的时候设置代理(第八部分实现)

    4 代码:(代理方法:滑动完成的时候调用)

    #pragma mark - 滑动完成的时候调用
    #pragma mark - scrollerView的代理方法(设置拖动scrollerView与标题button联动)
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        //计算拖动索引
        NSInteger index = scrollView.contentOffset.x / XFJ_screenW;
        //依据索引取出相应的button
        XFJTitleButton *titleButton = self.titleView.subviews[index];
        //方法
        [self titleButtonClick:titleButton];
    }

    十一 点击状态栏回到顶部

    1 该功能苹果内部已经帮我们实现了(方法一)

    2 使用这样的架构搭建的时候,点击状态栏,回到顶部的功能失效了

    3 失效原因:点击状态栏回到顶部,这样的功能仅仅针对UIScrollView才有效果,可是我们至少往控制器中加入了六个UIScrollView,全部状态栏无法识别.

    4 做法:禁止父控件ScrollView接收回到顶部的方法

    5 推断是否载入了view;推断view的类型是否是UIScrollView的类型

    —> 6 代码:
    /*
         设置点击顶部状态栏,内容回到顶部(仅仅有UIScrollerView才有这功能)
         */
        //遍历
        for (NSInteger i = 0; i < self.childViewControllers.count; i++) {
            //取出全部的子控制器
            UIViewController *childVC = self.childViewControllers[i];
            //推断假设没有载入了view就跳过
            if (![childVC isViewLoaded]) continue;
            //假设不是这样的类型就跳过
            if (![childVC.view isKindOfClass:[UIScrollView class]]) continue;
            //假设类型是UIScrollView的类型
            UIScrollView *scrollView = (UIScrollView *)childVC.view;
            scrollView.scrollsToTop = (i == index);
        }

    7 方法二:(不推荐使用)

    —> 7.1 在创建一个窗体,仅仅有在创建一个窗体,才不会遮住状态栏,可是这样做会引起一系列的问题,所以不推荐使用,可是这样的功能还是须要的.比方,非常多电商应用都在界面中设置了一个能够移动而且点击的购物车,这就是利用新创建的窗体实现的.所以这样的方法慎用.

    十二 全屏穿透

    1 设置内边距实现全屏穿透的效果,让tableView全部的内容都能在内容区域显示,而且顶部内容和底部内容不会被tabBar和导航条遮住

    2 实现代码:(必须在每个tableView控制器中都依次加入)

    //设置view的颜色
        self.tableView.backgroundColor = XFJ_randomColor;
        //设置内边距(内容的额外边距)
        self.tableView.contentInset = UIEdgeInsetsMake(99, 0, 49, 0);
        //设置tableView的滚动栏
        self.tableView.scrollIndicatorInsets = self.tableView.contentInset;

    十三 加入全部的子控制器(这部分没什么好介绍的,看懂即可)

    #pragma mark - 加入全部的tableView的view到内容的scrollerView
    - (void)setUpAllTableView
    {
        //加入子控制器
        [self addChildViewController:[[XFJAllViewController alloc] init]];
        [self addChildViewController:[[XFJPassageViewController alloc] init]];
        [self addChildViewController:[[XFJPictureViewController alloc] init]];
        [self addChildViewController:[[XFJVideoViewController alloc] init]];
        [self addChildViewController:[[XFJVoiceViewController alloc] init]];
    }

    十四 优化

    1 tableView的懒载入

    2 自己定义button的封装

    3 经过測试,假设按照以上的代码书写,能达到效果,可是我发现这样写的问题是tableView无法实现懒载入.原因是由于在第(八点),取出父控件中子控件的view的时候,在viewDidLoad中打印的结果显示,一開始就会创建5个tableView,所以不存在懒载入.

    4 改进方案:在点击button完成的时候,我们在创建而且加入button.

    —-> 4.1 代码块一:
    ......}completion:^(BOOL finished) {
    
            //加入相应的index到scrollerView中
            [self addChildVCIntoScrollView:index];
        }];
        4.2 方法:(内部做出了推断,假设父控件中存在view的时候,我们就不在创建)
    #pragma mark - 加入相应的子控制器的view到scrollerView中
    - (void)addChildVCIntoScrollView:(NSInteger)index
    {
        //依据相应的index取出相应的子控件器
        UIViewController *childVC = self.childViewControllers[index];
        //推断,假设子控制器已经载入过了,那么直接返回,不再加入了
        if ([childVC isViewLoaded]) return;
        //该句就是上面那句的简写
        childVC.view.frame = self.contentView.bounds;
        //将view加入到scrollerView中
        [self.contentView addSubview:childVC.view];
    }

    十五 知识点补充

    1 frame.size.height:矩形框的高度

    2 什么是tableView的内容(content)?

    —> 2.1 cell
    —> 2.2 tableHeaderView ableFooterView
    —> 2.3 sectionHeadersectionFooter

    3 contentSize.height:内容的高度

    4 contentOffset.y:内容的偏移量(frame的顶部-contentSize的顶部)

    5 contentInset:内容周围的间距(内边距) frame:以父控件内容的左上角为坐标原点

    十六 疑问

    1 问题: 须要当用户执行app的时候,默认第0个button为选中状态,而且button的下划线也默认在button的以下 ,可是执行的时候,下滑线没有显示出来

    —> 原因:在viewDidLoad中载入的时候顺序出了问题

    2 疑问:我们依次给每个tableView都加一个顶部内边距和底部内边距,是不是太累了,为什么不直接给tableView的父控件scrollerView直接加一个顶部内边距和底部内边距?

    —> 解答: scrollerView的子控件tableView会整个往下移动64的距离,同一时候全屏穿透效果消失.—>内边距影响

    3 非常多人拖动tableView滑动的时候,看到了tableView之间有一根绿色的线条,这不是bug,是模拟器的原因.

    十七 总结

    1 该部分解说全然解析了当下流行框架和仿百思的框架的搭建步骤,里面都解析到了全部发生的问题,希望能帮到大家.

    2 最后大家假设认为我的博客能满足大家的需求,希望能及时的给我留言,有什么问题的话,希望也及时给我留言.假设大家认为我的博客还能够的话,那么希望您关注我的官方博客,谢谢!!!!

  • 相关阅读:
    【转】NHibernate主键类型介绍
    【转】NHibernate 各种数据库配置
    NHibernate常见错误
    NHibernate 设置主键不自增长
    Oracle 同名字段的该行数据按照创建时间最新的隐藏其他
    不用第三个变量就能交换两个变量值的五个方法
    Java IO 要点总结
    Java API 各个包的内容解释
    Ways to 优化JAVA程序设计和编码,提高JAVA性能
    Java菜鸟入坑学习要点
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7358928.html
Copyright © 2020-2023  润新知