美文网首页UI适配知识点UI
iOS屏幕适配(纯代码)

iOS屏幕适配(纯代码)

作者: Mr_Victory | 来源:发表于2016-05-20 16:00 被阅读9425次
      在iOS实际项目开发中, 我们经常要适配不同尺寸的屏幕,如iPhone4s,iPhone5/s,iPhone6/s,iPhone6Plus等.  在代码中创建一个控件如:
    
    UILabel *label = [UILabel alloc] init];
    label.frame = CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);
    [self.view addSubView : label];
    
      我相信很多童鞋都是这么写的. 这样写也没有错. 但是当控件一多,设置控件的frame就成了一个难题. 有时候我们只能去估算控件的大小以及相对位置. 这样就有一个不好之处: 当你在一个设备上(如iPhone5s) 调整好了布局,那么当你运行在iPhone4s, 或者iPhone6s或者iPhone6s+ 上面的时候,你会发现原本已经布局好的界面变形了. 这就是由于屏幕尺寸的不同导致的问题.那我们该如何解决这个问题呢?  下面我将娓娓道来: 
      第一种方式也是我们经常使用的Autolayout(自动布局), 值得注意的是,Autolayout只适用 xib 跟 storyBoard.  Autolayout是一种“自动布局”技术,专门用来布局UI界面的.Autolayout自iOS6开始引入,由于Xcode4的不给力,当时并没有得到很大的推广.自iOS7(Xcode5)开始,Autolayout的开发效率得到很大的提升.苹果官方也推荐开发者使用Autolayout来布局UI界面.Autolayout能够很轻松的解决屏幕适配的问题.  它是通过在xib或者storyBoard中设置控件的依赖关系,从而适配.
      提到Autolayout,不得不提Autoresizing.在Autolayout以前,有Autoresizing可以做屏幕适配,但局限性较大,只能针对父子关系进行有限调整,如边距固定,尺寸可变,对于兄弟关系的调整无法实现.对于UI比较固定的app,这种方式基本满足.相比之下,Autolayout比Autoresizing强大很多.
      还有一个就是Size Classes.  Size Classes是iOS8中新增了特性,他是对当前所有iOS设备尺寸的一个抽象.  屏幕的宽和高分别分成三种情况:(Compact,Regular,Any).也就是紧凑,正常和任意. 这样宽和高三三整合,一共九种情况. 针对每一种情况,如果需要的话,我们可以单独在storyboard或xib中设置UIView的自动布局约束,甚至某一个button是否显示都是能轻松实现的. 具体使用方法这里就不做详细说明. 
      下面所要说的就是今天的重点: 纯代码实现屏幕适配. 在开始说之前,先让我们了解一下iPhone的机型和尺寸的对应关系:
    
    Snip20160520_1.png

    很明显能看出这三种屏幕的尺寸宽高比是差不多的,因此可以在5的基础上,按比例放大来适配6和6Plus的屏幕.

    // 在AppDelegate.h中
    @property float autoSizeScaleX;
    @property float autoSizeScaleY;
    
    // 在AppDelegate.m中
    #define ScreenHeight [[UIScreen mainScreen] bounds].size.height
    #define ScreenWidth [[UIScreen mainScreen] bounds].size.width
     
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];
       
        if(ScreenHeight > 480){ // 这里以(iPhone4S)为准
            myDelegate.autoSizeScaleX = ScreenWidth/320;
            myDelegate.autoSizeScaleY = ScreenHeight/568;
        }else{
            myDelegate.autoSizeScaleX = 1.0;
            myDelegate.autoSizeScaleY = 1.0;
        }
    }
    
      因为iPhone4s屏幕的高度是480, 因此当屏幕尺寸大于iPhone4时, autoSizeScaleX和autoSizeScaleY即为当前屏幕和iPhone5尺寸的宽高比, 比如,
    

    如果是5,autoSizeScaleX=1,autoSizeScaleY=1;
    如果是6,autoSizeScaleX=1.171875,autoSizeScaleY=1.17429577;
    如果是6Plus,autoSizeScaleX=1.29375,autoSizeScaleY=1.2957;
    现在我们获取了比例关系后,先来看一下如何解决代码设置界面时的适配。CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)这个方法使我们常用的设置尺寸的方法,现在我设置了一个类似于这样的方法。在.m文件中

    CG_INLINE CGRect
    TS_CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
    {
        AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];
        CGRect rect;
        rect.origin.x = x * myDelegate.autoSizeScaleX; 
        rect.origin.y = y * myDelegate.autoSizeScaleY;
        rect.size.width = width * myDelegate.autoSizeScaleX;
        rect.size.height = height * myDelegate.autoSizeScaleY;
        return rect;
    }
    
    当我们使用的时候直接这样做
    UIImageView *imageview = [[UIImageView alloc] initWithFrame:TS_CGRectMake(100, 100, 50, 50)];
    这样我们得出的就是转换后的坐标了. 这样,这个imageview在5,6和6Plus的位置和尺寸比例都是一样的. 妈妈再也不用担心屏幕的适配了.
    
      如果整个项目做完后才开始做适配的话这个方法的优势就体现出来了,面对几十个工程文件,只需自定义并且替换你的CGRectMake方法,再加上storyBoradAutoLay这个方法就瞬间完成大部分甚至全部的适配,如果遇到tableView的或者其他的手动调整一下即可. 
      当然这个我已经准备设计一个类, 写好了我会第一时间放在我的gitHub上,方便大家的使用.

    相关文章

      网友评论

      • MR_詹:我现在项目就是用这种方法,不过对于使用masonry设置间隙的,不够便捷,请问有没有推荐的方法
      • 4dbde41e70a3:1.请教:一些button是有背景图的,一般这种UI是不会标出宽高的,只能按照图片本身的大小来放置,但是无论是在什么机型上,图片最终呈现的大小是一样的,有什么办法将类似这种问题也适配完美啊,只有拉伸图片这一条路吗?
        2.写得这么清楚,有些人竟然要demo,给跪。赞作者
        :+1: :+1: :+1:
      • 那一处风景ljz:求贴出demo
      • 两岸青山:TS_CGRectMake的定义是要写在每一个要适配的页面里面吗?
      • 235a008fb19c:适配图片轮播出现问题了噢 填写的是屏幕的宽度,结果宽度填满不了
      • 直持小崔:不推荐 建议masroy 算布局不是coder的活
      • a69f8347d398:遇到有高度64的导航栏的, 这种方法就行不通了吧?
        juefeiye:如果是iPhone4这样的3.5寸屏幕,如果不能滚动,那么就内容的高度无法显示完全哦?理论上是这样,我还没有写代码验证
        Mr_Victory:@李印 这个64的高度差别不大
      • f1e24a8d40b9:这个方法我之前也用,不过楼主可以参考一下支付宝微信等app,5s到6p的情况下cell高度和首页button图片的大小是不变的,就是大小一致,间距变大而已,用之前同事说的一句话,手机大的意义在于可以显示更多东西,而不是在于把东西放大,支付宝等软件只是横向适配,确保5-6p上看起来是一致的
        Mr_Victory:@这小子1992 是的,多谢啦。
        Mr_Victory:是的,这个是比较老的做法了。 你说的的这个很好。感谢。
        这小子:同感啊!但是支付宝的的cell相对来说大屏手机就大了一点,之前拿5s,6,6p对比过了,有的控件还是等比适配的,UI做界面尽量让做6的界面,这样只是横向适配,纵向不需要适配的,一些轮播图之类的控件还是要做横纵向适配的
      • 码农_1:哥们,有demo吗? 麻烦给我来一份,万分感谢!!! 617964435@qq.com
        Mr_Victory:@码农_1 自己写个类,继承自NSObject
        码农_1:@Mr_Victory 就是那个重写的CGRect不知道写在哪里!
        Mr_Victory:这种方式适配不难啊, 就是算好屏幕缩放比例,然后使用CGRectMake 乘以缩放比例就好了。自己应该可以写出来啊。
      • 郑明明:你这种思路不错呀,和Masonry库的使用思想不同
        Mr_Victory:@NtZheng 是的,解决一个问题有很多种方法,主要看你愿不愿意思考。
      • ebay_Happy:大神请教下直接用frame做比例比较不也可以吗
      • 1d7b4829e23b:求demo哥们
      • hhgvg:楼主 我想问一下这个控件向左的距离在各个机型上是固定的?
        陌上北辰:@hhgvg 这个比例:20/320 *375
        hhgvg:@Mr_Victory 这个比例具体是有多大呢 怎么计算呢
        Mr_Victory:@hhgvg 这个不固定。比如你以iPhone5s为基准,距离左边20,那么在6上面因为6的屏幕宽于5s,那么它会乘一个比例,会比20要大
      • 47号同学:有demo吗?可以的话能发一下邮箱吗?993597571@qq.com
      • tztTzt:有没有考虑直接用runtime 动态修改 这样就不用一个一个修改了
        iOS之星:@一个帅气网名 runtime 把原生的方法替换成你自己写的方法, 然后在方法里去改变屏幕比例
        492b9b7cf804: @wry如意 请问runtime怎么做呢?能说下大致思路吗?
        Mr_Victory:@wry如意 这个暂未考虑,可以试一试
      • tztTzt:写的不错啊,有些老项目还在用frame的

      本文标题:iOS屏幕适配(纯代码)

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