看源码的时候,发现了一个flat的用法,来返回一个新的cgfloat数值,为了弄懂为什么要这么做,我们来看一下
/**
* 基于指定的倍数,对传进来的 floatValue 进行像素取整。若指定倍数为0,则表示以当前设备的屏幕倍数为准。
*
* 例如传进来 “2.1”,在 2x 倍数下会返回 2.5(0.5pt 对应 1px),在 3x 倍数下会返回 2.333(0.333pt 对应 1px)。
*/
CG_INLINE CGFloat
flatSpecificScale(CGFloat floatValue, CGFloat scale) {
scale = scale == 0 ? ScreenScale : scale;
CGFloat flattedValue = ceil(floatValue * scale) / scale;
return flattedValue;
}
如果说苹果设备是固定ppi ,那就好计算了。。截了一份官网的ppi
,除了这个之外还有watch 设备等。。。拿这个去做适配得算死
苹果系统会假设你编程都是72dpi 。然后再自动适应,。
如果是这样 72pt = 72px , 1pt = 1px
这样你还是只用关心px,反正和pt是相等的,他设备会自己算,
后来出现了高分辨率屏幕,如果还按照px来做,为在不同像素密度的屏幕里面,像素本身大小是不一样的,会导致尺寸乱了。。。
dpi高了以后就出现了 1pt = 2px ,
1pt = 3px 就是我们平常用的@2x @3x图
然后就苹果设备会自己做适配。
所以你在运行时打印的pt 对应的px数值是根据你所运行的设备决定
的
说了这么多,现在可以开始尝试理解代码了。
运行期间到底是几倍呢?苹果有个函数
[[UIScreen mainScreen] scale];
1 pt = scale * px
如果这个px 数值越多。就是说一个点上有更多的光栅方形格子
光栅格子是啥意思 参考这篇文章
就是我之前纠结的1pt 到底等于多少px 的数值参考文章
比如说4s scale 就是2 ,会使用@2x的图片, 6+就是3,会使用@3x的图片,
iPhone6+在实际时,downsampling/1.15(1242x2208->1080x1920)
, 苹果为方便开发者用的是@3x的素材,然后再缩放到@2.46x上。
因为ip6+实际物理像素比屏幕像素压缩了1.15倍。但是为了开发者方便还是只要提供@3x图就好了,苹果是会自己缩放的。
回到这个公式
ceil(floatValue * scale)/ scale
这个意思是向下取整,比如一个floatValue数值为24.3,在ip6+的屏幕上
scale = 3
floatValue * scale=72.900000000000006
ceil(72.900000000000006) = 73 (这个是实际屏幕的显示的大小)
73 /scale = 24.333333333333332 (这个是代码中应该写的数值,来保证屏幕实际大小是73)
为什么要保证屏幕尺寸取最小值呢,
ceil
代表向下取整,是为了最大限度处理像素吧,不要出现<1的方格, px 放在pt里面就是一个pt 对应多少个px数值,
像素说到底是一个方格,0.00001个方格怎么放,就不好说了,因为普通意义上这个方格就是最小的点了,苹果系统应该会忽略他,至于怎么忽略,我们就不知道了。所以可以自己把方格数量取整,就不会出现像素有预想的偏移量了。
最后补充一下image 要用imageNamed初始化的原因
以下基于UIImage的两类初始化API简介高倍图的适配:
同时该API根据UIScreen的scale,
自动查找包含对应高倍图后缀名(@2x)的文件,如果找到二倍图,
则image.scale=2.0,
对应逻辑size大小以point度量(pixel度量的一半);
如果没找到设置默认image.scale=1.0,
对应逻辑size大小同像素尺寸。
因此,使用该方法,无需特意指定高倍图后缀。
在实际运行时,系统如果发现当前设备是Retina屏(scale=2),
会自动寻找"*@2x.png"命名格式的图片,
加载针对Retina屏的图片素材,否则会失真。
如果是label 记得添加了文字后 要用sizetoFit
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 110, 150)];
label.backgroundColor = [UIColor orangeColor];
[self.view addSubview:label];
/*
CGRectGetHeight返回label本身的高度
CGRectGetMinY返回label顶部的坐标
CGRectGetMaxY 返回label底部的坐标
CGRectGetMinX 返回label左边缘的坐标
CGRectGetMaxX 返回label右边缘的坐标
CGRectGetMidX表示得到一个frame中心点的X坐标
CGRectGetMidY表示得到一个frame中心点的Y坐标
*/
这个是框架做的横屏适配,之后我也 会按照这种写法。
//左边视图宽度 = 滚动视图宽度 / 2, 右边视图宽度 = 滚动视图宽度- 左边视图宽度;
CGFloat leftWidth = flat(CGRectGetWidth(self.scrollView.bounds) / 2);
CGFloat rightWidth = CGRectGetWidth(self.scrollView.bounds) - leftWidth;
//左边视图高度 = logo图高度 + label顶部距离 + label高度
CGFloat leftHeight = CGRectGetHeight(self.logoImageView.frame) + versionLabelMarginTop + CGRectGetHeight(self.versionLabel.frame);
//左边视图最小Y数值 = (滚动视图高度 - 导航栏的底部高度)- 左边视图高度 /2;来保证 左边视图全部居中
CGFloat leftMinY = CGFloatGetCenter(CGRectGetHeight(self.scrollView.bounds) - CGRectGetMaxY(self.navigationController.navigationBar.frame), leftHeight);
//logo图的frame = logo图的rect x =(左边视图宽度 -logo图宽度)/2 y = 最小y数值
self.logoImageView.frame = CGRectSetXY(self.logoImageView.frame, CGFloatGetCenter(leftWidth, CGRectGetWidth(self.logoImageView.frame)), leftMinY);
//版本label frame = 版本label的rect x = 和logo图的水平居中的位置 y = logo图加上高度
self.versionLabel.frame = CGRectSetXY(self.versionLabel.frame, CGRectGetMinXHorizontallyCenter(self.logoImageView.frame, self.versionLabel.frame), CGRectGetMaxY(self.logoImageView.frame) + versionLabelMarginTop);
//右边内容宽度 = 右边视图宽度 - 左右两边的边距
CGFloat contentWidthInRight = rightWidth - UIEdgeInsetsGetHorizontalValue(padding);
//访问官网的frame x = 左边宽度 + pading距离 y = logo图片的顶部 + 10 宽度 = 右边内容宽度 高度
self.websiteButton.frame = CGRectMake(leftWidth + padding.left, CGRectGetMinY(self.logoImageView.frame) + 10, contentWidthInRight, buttonHeight);
//功能列表的frame rect 和访问官网一致 y 和访问官网底部一致
self.documentButton.frame = CGRectSetY(self.websiteButton.frame, CGRectGetMaxY(self.websiteButton.frame));
//同上
self.gitHubButton.frame = CGRectSetY(self.documentButton.frame, CGRectGetMaxY(self.documentButton.frame));
//copyRightLabel 的高度 = 自适应一下,传入宽度 右边内容宽度
CGFloat copyrightLabelHeight = [self.copyrightLabel sizeThatFits:CGSizeMake(contentWidthInRight, CGFLOAT_MAX)].height;
//copyRightLabel frame x = 左边宽度 + pading距离 y = 滚动视图高度 - 导航条底部 - 底部底部边距 - 高度,
self.copyrightLabel.frame = CGRectFlatMake(leftWidth + padding.left, CGRectGetHeight(self.scrollView.bounds) - CGRectGetMaxY(self.navigationController.navigationBar.frame) - padding.bottom - copyrightLabelHeight, contentWidthInRight, copyrightLabelHeight);
//滚动视图内容区域 = 宽度 为 屏幕宽度 高度=屏幕高度 - 导航栏的高度
self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - CGRectGetMaxY(self.navigationController.navigationBar.frame));