美文网首页
Frame布局入门看我就够了

Frame布局入门看我就够了

作者: 飞飞超人 | 来源:发表于2019-07-18 11:26 被阅读0次

    初识

    在IOS中最常用的两种布局方式是Frame布局和AutoLayout布局。本文主要讲解Frame布局的相关知识。
    Frame布局使用简单,适合初学者,可以采用手写或者xib进行布局,适用于比较简单的界面布局,复杂的布局如果使用Frame布局逻辑会很复杂,不利于布局和后期维护。
    Frame的数据结构简单,类型为CGRect,其中original属性定义point,size属性定义大小,初始化成功一个Frame布局之后,可以使用setFrame修改布局。frame的值影响自己的布局,bounds只影响其子view的布局。

    UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
    [self.view addSubview:view];
    

    适用场景

    有时候会遇到一些稍微复杂度一点的界面布局,这时候可以使用函数或者对象封装原生的frame布局方法,好的封装让我们可以使用链式布局[^1]的方法,和更简单的方式进行frame布局。
    已经有前人实现了frame布局的相对布局[5]
    也有三方库支持像使用masory一样使用frame布局[6]和[7]
    但是很复杂的界面就不建议使用frame布局了,可以使用autolayout布局,当然还有其它布局方式,这儿不讨论。
    Frame布局的效率比AutoLayout高得多,下面是他们的效率比较图表。


    performance.png

    图片来源和性能分析更详细可参考[2]

    调试

    可以使用系统自带的debug view hierachy和第三方的Reveal查看当前界面的布局情况。

    Debug view hierachy:


    debug1.png

    Reveal:


    debug2.png
    可以在lldb中使用po查看view的frame值,这也是我们调试界面布局的一个重要参考指标,如果不能查看,需要手动在lldb中运行e @import UIKit,然后po就可以了。(如果不清楚po是什么,需要先去看下lldb的基础知识)

    Frame动画

    可以通过改变frame布局的值来实现一些简单的动画,当然这儿不使用frame是因为
    一般外部使用view,使用frame;内部使用或者定义view,使用bounds;动画和旋转一般基于center来进行,很少通过操作frame。

    [UIView animateWithDuration:0.5 animations:^{
                    
           self.view.center = CGPointMake(20, 20);
                    
           } completion:^(BOOL finished) {
                        
                        //do something       
     }];
    

    Frame的本质

    每个view都有一个frame,这个frame实际是layer的frame,view只是透传frame的值。修改view的frame布局,其实修改的是layer的frame布局。
    Frame属性只是一个计算属性,它最后的值由bounds,anchor,position和transform这几个实际属性计算获得,他们之间会相互影响。具体的算法如下,参考文章[3]和参考[4]。
    下面是frame计算的伪代码

    
     -(CGRect)frame
    {
          CGRect retValue = CGRectZero;
          if (CGAffineTransformIsIdentity(self.transform))
          { //没有设置仿射变换的情况下
               
                //位置等于中心点的位置减去视图尺寸乘以锚点的值。
                retValue.origin.x = self.center.x - self.bounds.size.width * self.layer.anchorPoint.x;
                retValue.origin.y = self.center.y - self.bounds.size.height * self.layer.anchorPoint.y;
               //尺寸等于视图的尺寸
                retValue.size.width = self.bounds.size.width;
                retValue.size.height = self.bounds.size.height;
          }
          else
          {
                CGAffineTransform left =  CGAffineTransformMakeTranslation(-1 * self.bounds.size.width * self.layer.anchorPoint.x, -1 * self.bounds.size.height * self.layer.anchorPoint.y);
                //因为下面的坐标变换应用是从(0,0)开始的,因此这里的right指定中心点的位置,也就是下面的复合变换右乘right来实现位置的变换处理。
                CGAffineTransform right =  CGAffineTransformMakeTranslation(self.center.x, self.center.y);
                //整个复合变换是left 左乘 视图的tansform属性然后再右乘right变换。
                CGAffineTransform concat  = CGAffineTransformConcat(CGAffineTransformConcat(left, self.transform), right); 
                retValue  = CGRectApplyAffineTransform(CGRectMake(0,0,self.bounds.size.width, self.bounds.size.height), concat);
          }
    
        return retValue
    }
    
    

    立即刷新Frame

    frame布局可以使用setneedlayout设置刷新布局标志位,如果需要立即刷新调用layoutifneed方法,会立即触发调用layoutsubviews,你可以在这个接口中做很多事,比如你可以在这个接口里面刷新它父亲的布局。

    @implementation ViewController
    
    -(void)viewDidLayoutSubviews
    {
        //Second
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        UIView* test = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 20, 20)];
        test.backgroundColor = [UIColor blackColor];
        
        [self.view addSubview:test];//First
        
        [self.view layoutIfNeeded];
        
        NSLog(@"3");    //Third
    }
    
    
    @end
    
    

    从上述代码中的First,Second和Third可以看出执行顺序。

    Autoresizingmask

    使用Autoresizingmask,系统会自动生成frame布局,并且这个布局在父view变化的时候会跟随变化。

    适配

    frame布局在处理适配的问题上比autolayout需要做更多工作。frame布局在适配不同的机型上可能会出现很多的魔法变量,当然可以用宏定义解决一部分问题,但是会使得后期难以维护和理解,毕竟代码大部分时间都是用来阅读的,所以可读性还是很重要的。

    [1] 链式布局:https://www.jianshu.com/p/67fd5332e7b9

    [2] 性能分析:https://draveness.me/layout-performance

    [3] Frame计算:https://www.jianshu.com/p/a12cc7356c99

    [4] Frame计算:https://www.jianshu.com/p/00482643234d

    [5] Frame相对布局:https://github.com/huisedediao/UIView-FrameLayout

    [6] Frame相对布局:https://www.jianshu.com/p/d99e94e6b9f9

    [7] Frame相对布局:https://www.jianshu.com/p/b76947766583

    相关文章

      网友评论

          本文标题:Frame布局入门看我就够了

          本文链接:https://www.haomeiwen.com/subject/cobklctx.html