IOS 屏幕适配(纯粹通过代码设置坐标和大小的布局方案)

看了网上有很多屏幕适配的文章,大多是用iOS的相对布局来实现屏幕适配(autoLayout,Masonry)

一些文章主要解决,iphone6/6p刚出来时,以前只解决屏幕高度适配,现在也要解决屏幕宽度适配的问题。

本文主要解决,项目已经过度过来,但做新的页面时,UI给的设计往往只有iphone6的尺寸,如何向下兼容

iphone4s/iphone5/5s,向上兼容6p。


你可能遇到以下问题,按照UI的设计标注做完了,自己没做兼容性测试,只是在模拟器上OK,就提交测试了。

接下来问题来了,UI,测试,产品,在不同机器上看到页面,觉得没有按照UI设计来,自己觉得很冤枉啊,但

没办法,在非iphone6机器上确实很丑陋,有时交互都有问题,又改一通,有没有办法,一次搞定呢,不让他们

有机会秋后算帐。


相信有很多人跟我一样不太适应iOS的相对布局,下面介绍一下,如何通过绝对布局完美解决屏幕适配问题。


获取屏幕高度


最好宏定义,因为很多地方用。

func ScreenBounds() -> CGRect {

    return UIScreen.mainScreen().bounds

}


//MARK: 获取设备的物理高度

func ScreenHeight()->CGFloat {

    return ScreenBounds().height

}


//MARK: 获取设备的物理高度

func ScreenWidth()->CGFloat {

    return ScreenBounds().width

}


简单页面的适配(可滑动的列表页面)


列表高度= 屏幕高度 - 头部高度 -底部高度

列表宽度 = 屏幕宽度


//MARK: ios7中对y坐标的修订,状态栏高度

func IOS7_ORIGINAL_Y_FIXED() -> CGFloat {

    return IfIOS7() ? 22.0 : 0.0

}

//MARK: 获取界面顶部header的高度

func gainHeaderHight() -> CGFloat {

    return IOS7_ORIGINAL_Y_FIXED() + NAVIGATION_BAR_HEIGHT

}


//MARK: 获取界面中除了顶部header部分的高度

func gainExceptHeaderHight() -> CGFloat {

    return ScreenHeight() - (IOS7_ORIGINAL_Y_FIXED() + NAVIGATION_BAR_HEIGHT)

}



复杂页面的适配 (满屏页面不可滑动,多为某功能模块首页)


定义各种屏幕相对iphone6屏幕的宽高比率R,对页面元素布局时,按照UI标注,再乘以R,

得到适配屏幕的坐标和大小。

//MARK: 获取设备相对于iPhone6屏幕尺寸的比例

let ScreenScaleX = ScreenWidth()/375.0

let ScreenScaleY = ScreenHeight()/667.0


private let HeadImageViewSize: CGFloat = 150 * ScreenScaleX


这样布局完页面基本可以不用秋后算帐了。


如果页面确实很紧凑,页面就要添加scrollview,小屏幕时,向下滑动。那就是另外一种适配方案了。


复杂页面中的子页面按比例设置宽高间距

如果按上面设置坐标和大小后,发现页面还没完全适配,那么需要将其中一个子页面中的控件坐标,

以所占整个控件的比例来设置,比例则通过UI标注值计算得来。

    private let h1:CGFloat = 828                //情形1总高度

    private let upMargin1:CGFloat = 114         //情形1顶部距离

    private let imageHeight1:CGFloat = 330      //情形1图像高度

    private let imgToLabelMargin1:CGFloat = 94  //情形1图像和文本间距离

    private let labelToLabelMargin1:CGFloat = 28//情形1文本和文本间距离

//计算而得

    private var upRadio1:CGFloat = 0.0

    private var imageReadio1:CGFloat = 0.0

    private var imgToLabelRadio1:CGFloat = 0.0

    private var labelToLabelRadio1:CGFloat = 0.0

override init(frame: CGRect) {

        super.init(frame: frame)

        

        upRadio1 = upMargin1/h1

        imageReadio1 = imageHeight1/h1

        imgToLabelRadio1 = imgToLabelMargin1/h1

        labelToLabelRadio1 = labelToLabelMargin1/h1

...

imgView.po_frameBuilder().setSize(CGSizeMake(bounds.height*imageReadio1, bounds.height*imageReadio1)).alignToTopInSuperviewWithInset(bounds.height*upRadio1).centerHorizontallyInSuperview()

        

        label1.sizeToFit()

        label1.po_frameBuilder().alignToBottomOfView(imgView, offset: bounds.height*imgToLabelRadio1).centerHorizontallyInSuperview()

        

        label2.sizeToFit()

        label2.po_frameBuilder().alignToBottomOfView(label1, offset: bounds.height*labelToLabelRadio1).centerHorizontallyInSuperview()

}



字体的适配


如果UI对字体也很挑剔,明明按他的设计上的字体赋值的,但再小屏幕机器上她觉着大,肿么办呢?

针对不同设备,字体宏定义为不同大小。

func  Macro_Relative_Font_23() -> UIFont {

    if IS_IPHONE6() {

        return UIFont.systemFontOfSize(23.0)

    } else if IS_IPHONE5() {

        return UIFont.systemFontOfSize(20.0)

    } else {

        return UIFont.systemFontOfSize(18.0)

    }

}


cancelBtn.titleLabel?.font = Macro_Relative_Font_16()



一些方法论参考

屏幕适配的那些坑

http://www.cocoachina.com/ios/20141215/10634.html


推荐一个好用的布局库

POViewFrameBuilder是一组UIViewCategory和帮助类,可以大大方便在代码中操纵UIViewframe,节省不必要的麻烦计算。提供centerInSuperView, setWidth, setHeight这样方便的帮助函数

你可能感兴趣的:(#,IPhone开发高级系列)