iOS: 如何正确的绘制1像素的线
2015-08-18 11:32
411 查看
一、Point Vs Pixel
iOS中当我们使用Quartz,UIKit,CoreAnimation等框架时,所有的坐标系统采用Point来衡量。系统在实际渲染到设置时会帮助我们处理Point到Pixel的转换。
这样做的好处隔离变化,即我们在布局的事后不需要关注当前设备是否为Retina,直接按照一套坐标系统来布局即可。
实际使用中我们需要牢记下面这一点:
1 Point的线在非Retina屏幕则是一个像素,在Retina屏幕上则可能是2个或者3个,取决于系统设备的DPI。
iOS系统中,UIScreen,UIView,UIImage,CALayer类都提供相关属性来获取scale factor。
原生的绘制技术天然的帮我们处理了scale factor,例如在drawRect:方法中,UIKit自动的根据当前运行的设备设置了正切的scale factor。所以我们在drawRect: 方法中绘制的任何内容都会被自动缩放到设备的物理屏幕上。
基于以上信息可以看出,我们大部分情况下都不需要去关注pixel,然而存在部分情况需要考虑像素的转化。
例如画1个像素的分割线
看到这个问题你的第一想法可能是,直接根据当前屏幕的缩放因子计算出1 像素线对应的Point,然后设置线宽即可。
代码如下:
表面上看着一切正常了,但是通过实际的设备测试你会发现渲染出来的线宽并不是1个像素。
Why?
为了获得良好的视觉效果,绘图系统通常都会采用一个叫“antialiasing(反锯齿)”的技术,iOS也不例外。
显示屏幕有很多小的显示单元组成,可以接单的理解为一个单元就代表一个像素。如果要画一条黑线,条线刚好落在了一列或者一行显示显示单元之内,将会渲染出标准的一个像素的黑线。
但如果线落在了两个行或列的中间时,那么会得到一条“失真”的线,其实是两个像素宽的灰线。
如下图所示:
官方解释如上,简单翻译一下:
如何对齐呢?
翻译一下
如下图所示:
看了上述一通解释,我们了解了1像素宽的线条失真的原因,及解决办法。
至此问题貌似都解决了?再想想为什么在非Retina和Retina屏幕上调整位置时值不一样,前者为0.5Point,后者为0.25Point,那么scale为3的6 Plus设备又该调整多少呢?
要回答这个问题,我们需要理解调整多少依旧什么原则。
再回过头来看看这上面的图片,图片中每一格子代表一个像素,而顶部标记的则代码我们布局时的坐标。
可以看到左边的非Retina屏幕,我们要在(3,0)这个位置画一条一个像素宽的竖线时,由于渲染的最小单位是像素,而(3,0)这个坐标恰好位于两个像素中间,此时系统会对坐标3左右两列的像素对填充,为了不至于线显得太宽,为对线的颜色淡化。那么根据上述信息我们可以得出,如果要画出一个像素宽的线,就得把绘制的坐标移动到(2.5, 0)或者(3.5,0)这个位置,这样系统渲染的时候刚好可以填充一列像素,也就是标准的一个像素的线。
基于上面的分析,我们可以得出“Scale为3的6 Plus”设备如果要绘制1个像素宽的线条时,位置调整也应该是0.5像素,对应该的Point计算如下:
奉上一个画一像素线的一个宏:
使用代码如下:
二、正确的绘制Grid线条
贴上一个写的GridView的代码,代码中对Grid线条的奇数像素做了偏移,防止出现线条模糊的情况。
SvGridView.h
SvGridView.m
使用方法如下:
三、一个问题
好了,到这儿本文的全部知识就结束了,最后我还有一个问题。
设计师为什么一定要一个像素的线?
一个像素的线可能在非Retina设备上显示宽度看着合适,在Retina屏幕上显示可能会比较细。是不是一定需要一个像素的线,需要根据情况来处理。
参考文档:
https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html
注:smileEvday保留本文的一切权利
iOS中当我们使用Quartz,UIKit,CoreAnimation等框架时,所有的坐标系统采用Point来衡量。系统在实际渲染到设置时会帮助我们处理Point到Pixel的转换。
这样做的好处隔离变化,即我们在布局的事后不需要关注当前设备是否为Retina,直接按照一套坐标系统来布局即可。
实际使用中我们需要牢记下面这一点:
iOS系统中,UIScreen,UIView,UIImage,CALayer类都提供相关属性来获取scale factor。
原生的绘制技术天然的帮我们处理了scale factor,例如在drawRect:方法中,UIKit自动的根据当前运行的设备设置了正切的scale factor。所以我们在drawRect: 方法中绘制的任何内容都会被自动缩放到设备的物理屏幕上。
基于以上信息可以看出,我们大部分情况下都不需要去关注pixel,然而存在部分情况需要考虑像素的转化。
例如画1个像素的分割线
看到这个问题你的第一想法可能是,直接根据当前屏幕的缩放因子计算出1 像素线对应的Point,然后设置线宽即可。
代码如下:
Why?
为了获得良好的视觉效果,绘图系统通常都会采用一个叫“antialiasing(反锯齿)”的技术,iOS也不例外。
显示屏幕有很多小的显示单元组成,可以接单的理解为一个单元就代表一个像素。如果要画一条黑线,条线刚好落在了一列或者一行显示显示单元之内,将会渲染出标准的一个像素的黑线。
但如果线落在了两个行或列的中间时,那么会得到一条“失真”的线,其实是两个像素宽的灰线。
如下图所示:
看了上述一通解释,我们了解了1像素宽的线条失真的原因,及解决办法。
至此问题貌似都解决了?再想想为什么在非Retina和Retina屏幕上调整位置时值不一样,前者为0.5Point,后者为0.25Point,那么scale为3的6 Plus设备又该调整多少呢?
要回答这个问题,我们需要理解调整多少依旧什么原则。
再回过头来看看这上面的图片,图片中每一格子代表一个像素,而顶部标记的则代码我们布局时的坐标。
可以看到左边的非Retina屏幕,我们要在(3,0)这个位置画一条一个像素宽的竖线时,由于渲染的最小单位是像素,而(3,0)这个坐标恰好位于两个像素中间,此时系统会对坐标3左右两列的像素对填充,为了不至于线显得太宽,为对线的颜色淡化。那么根据上述信息我们可以得出,如果要画出一个像素宽的线,就得把绘制的坐标移动到(2.5, 0)或者(3.5,0)这个位置,这样系统渲染的时候刚好可以填充一列像素,也就是标准的一个像素的线。
基于上面的分析,我们可以得出“Scale为3的6 Plus”设备如果要绘制1个像素宽的线条时,位置调整也应该是0.5像素,对应该的Point计算如下:
贴上一个写的GridView的代码,代码中对Grid线条的奇数像素做了偏移,防止出现线条模糊的情况。
SvGridView.h
好了,到这儿本文的全部知识就结束了,最后我还有一个问题。
设计师为什么一定要一个像素的线?
一个像素的线可能在非Retina设备上显示宽度看着合适,在Retina屏幕上显示可能会比较细。是不是一定需要一个像素的线,需要根据情况来处理。
参考文档:
https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html
注:smileEvday保留本文的一切权利
相关文章推荐
- 【iOS开发】iOS下使用FFMPEG的一些总结
- 获取iOS应用的URL Schemes
- IOS开发之简单计算器
- iOS 自定义TabBarController
- 9秒学院-iOS开发新手需必备
- iOS开发 -- 更改placeholder的字体颜色、大小
- 漫谈iOS Crash收集框架
- 苹果开发者后台的帮助文档
- 分享一些学习iOS的开发心得
- 浅谈iOS学习心得
- iOS开发常用快捷键
- 苹果开发 笔记(62)edgesForExtendedLayout
- iOS-不用viewController 而是用拖来的table view controller 会黑屏
- iOS高级-数据存取
- iOS 类簇(Class Cluster)使用心得
- iOS操作属性列表plist(增删改查)
- ios至于理解锚
- Xcode7真机调试iOS应用程序
- iOS 6.0之后支持一个页面横屏的方法
- iOS 常见系统库作用以及KVC和KVO的关系