Mac平台retina高分屏开发技术分享
转自:http://iblog.tencent.com/mac-retina-guide/
QQ for Mac V2.1版本支持了Retina,作为国内首个支持Retina高分屏的Mac OS X App,我们希望能够和大家分享一些在Retina支持方面的开发技术心得。欢迎Mac平台的开发朋友们与我们沟通交流。也希望可以通过iblog这个平台在今后和大家交流Mac OS X系统方面的技术经验。
基本概念和思想
和iOS的异同
在系统对高分屏的支持上,Mac OS和iOS基本上是一样的:都是两倍的Scale Factor,都是系统自动来完成这个Scaling。但Mac OS毕竟是电脑操作系统,与iOS相比,多了对以下几个方面的支持:
- window和screen的关系
- 多显示器
- 显示器分辨率的随时更改
两种运行模式:Framework-Scaled和Magnified
在高分屏的Mac中,App有两种运行模式: Framework-Scaled模式和Magnified模式。两种模式的差别,在于Backing Store层的大小。什么是Backing Store层?我们的App和显示器之间,其实有一层buffer层,这层就是Backing Store层。在Framework-Scaled模式下,Backing Store层的大小和显示器一样,而Magnified模式时是显示器的四分之一(长宽各为二分之一),相当于同尺寸普通屏的大小。
在Framework-Scaled模式下,因为Backing Store层的大小和显示器一样,所以我们的App可以更精细地做视觉处理。而与之相比,Magnified模式其实是一个纯粹为兼容而设计的模式。在Magnified模式下,因为Backing Store层的大小和普通屏一样,App还是以1x的形式运行,在显示时,即Backing Store层到显示器的转换时,系统再把其拉伸到2x。这样,在Magnified模式下的App会保持和普通屏一致的表现,当然,也会因拉伸而看上去有点模糊。
非Cocoa的App则只能以Magnified模式运行,而Cocoa App默认是以Framework-Scaled模式运行。 如果Cocoa App觉得自己在Framework-Scaled模式下运行有较大体验问题,也可以在程序中将自己设成默认以Magnified模式运行。 此外,用户也可以通过程序文件的“显示简介”窗口手动更改App的运行模式。
毫无疑问,要在高分屏上有细腻的视觉感受,我们的程序必须运行在Framework-Scaled模式下。
Point和Pixel
什么是Point?苹果给的定义是用户空间的一个单位。在普通屏上,Point和Pixel是一比一的关系,而在高分屏上,它们的关系是一比四。这点和iOS是一样的。
对开发者来说,大部分情况下,我们根本不需要去考虑Pixel,因为我们程序中用到的坐标基本上都是以Point为单位的。在编写代码时,我们可以这样假设:世界上根本就不存在高分屏的Mac,新的MacBook Pro其实还是原来的1440*900。这样,我们就会都是以Point的方式去考虑坐标,从而保持程序高分屏和普通屏表现的一致性。这也是苹果推荐的方式。
那我们什么时候才需要考虑到Pixel呢?当我们准备操纵像素的时候。主要有以下几个地方:
- Core Graphics。也就是说,当我们用到CG开头的API时,我们需要注意,它们的坐标大部分是以Pixel为单位的。
- OpenGL。既然是绘制,自然要精确到像素级。
DPI和PPI
DPI:Dots Per Inch,每英寸点数,一般用来表示打印机或显示设备的精度。而在图像中,则一般使用PPI。
PPI:Pixels Per Inch,每英寸像素数,一般用来表示图像的精细度。
高分屏的DPI是144,是普通屏的两倍。此外,用系统截图工具截取的图片,其PPI也是144,同样是普通屏时的两倍。
支持高分屏,我们需要做些什么?
确认我们App运行在Framework-Scaled模式下
Cocoa App默认是以Framework-Scaled模式运行,不用做任何额外的事情。对于非Cocoa的App,如果要支持高分屏,需要做些修改了。
增加两倍图资源
和iOS一样,要支持高分屏,对所有图片,我们都需要在其旁边增加一个名字为“一倍图名字+@2x”的两倍图资源。对原来用图数量就比较多的程序来说,如QQ,设计师的工作量毫无疑问是巨大的。不仅如此,因为Mac窗体大小不像iOS那么统一,为了防止问题发生,切图时还要注意以下事项:
- 两倍图的图片资源,其分辨率最好是一倍图严格的两倍;PPI和一倍图保持一样,还是72。如果不这样做,不仅在高分屏上有可能出现不符合我们预想的表现,普通屏也是会受影响的。这是因为这些错误有可能会导致系统判断两倍图关系失败,从而使普通屏下直接读取两倍图,导致界面展示异常。
- 如果程序中还涉及到图片的叠加,那么这些用来叠加的图片,内容上最好也是严格的两倍。举个例子,如果一倍图中有根线的位置是第三行,那么两倍图中这根线的位置应该是第五行和第六行。否则,会出现在普通屏下对齐的图片在高分屏下却没有对齐的情况。
确认代码中的资源图片读取方法
要想让系统帮我们自适应使用一倍图和两倍图,我们最好尽量使用文档推荐的资源图片读取方法:NSImage的imageNamed:方法和NSBundle的imageForResource:方法,分别对应main bundle和其他bundle中图片的读取。如果之前代码中有使用其他资源图片读取方法的地方,最好替换掉。
确认资源图片读取时不要带后缀名
和iOS一样,如果我们想让系统自适应来使用一倍图和两倍图,读取时传入的图片名字就不能带有后缀名,否则读取的是那张指定名字的一倍图。xib中也是一样的情况。所以,请搜索全程序确认这点。
确认之前涉及图片size的代码是否有问题
NSImage的size是以Point为单位的,所以无论一倍图还是两倍图,其size都是一样的。而前面讲过CG层又是以Pixel为单位的,所以请详细检查转换时的代码。
检查有图片拉伸的地方是否有异常
首先注意一点, 拉伸图片时,系统会自动使用两倍图。这是因为,NSImage读取图片时其实是两幅图同时读入的,使用时再根据目标区域的大小决定使用哪张图。如果目标区域的大小是介于一倍图和两倍图之间,那么系统会使用两倍图,然后将其缩到目标区域大小。所以要注意喽,如果之前程序中有目标区域比图片大,那么赶紧确认下是否还表现正常,因为这里会使用两倍图的。
当然,如果需要,我们可以不让系统不这么做。通过NSImage的类方法setMatchesOnlyOnBestFittingAxis: 设定后,一倍图和两倍图就严格根据普通屏和高分屏来使用了。不过需要注意,该方法是10.7.4才有的。
一般来说,最好使用NSDrawThreePartImage和NSDrawNinePartImage来拉伸图像。
增加Point与Pixel的转换代码
之前因为普通屏下Point与Pixel是一比一的关系,所以有些代码无意中会将这两种坐标弄混。所以,最好确认下这方面的代码,特别是和屏幕相关的地方。
需要Point与Pixel之间的坐标转换时,使用Backing Coordinate System。NSView、NSWindow和NSScreen都有与其坐标转换的方法,尽量不要直接使用Scale Factor进行计算。
增加分辨率变化时的响应代码
前面提过,与iOS相比,Mac是支持多显示器和随时切换分辨率。当一个窗体在两个不同显示模式的显示器里来回拖拽时,这个窗体的显示模式和分辨率同时也在发生着变化。不过别担心,一旦这些发生变化,系统会自动帮我们重绘窗体,一倍图和两倍图之类的也会自动帮我们切换。不过,我们最好还是确认下,在发生这些变化的情况下,我们的表现是否还是正常的。
如果需要在显示模式切换时做些处理时,我们可以监听NSWindowDidChangeBackingPropertiesNotification。如果是自定义NSView,可以重载viewDidChangeBackingProperties方法,在里面做处理。
注意高分屏时截取的图像其PPI是144
当我们通过系统截图工具或QQ在高分屏中进行截图时,就会发现截取后的图像,其PPI是144,是普通屏的两倍。这并不难理解,因为高分屏单位距离的像素数就是普通屏的两倍。所以程序中使用截图的地方,要注意这点。
替换API
1)Base Coordinate System相关
之前我们会经常使用Base Coordinate System来表示在window中的坐标,而这个坐标系因为高分屏将被抛弃。所以,和这个坐标系相关的API,我们最好都要替换掉。
NSView:
convertPointToBase:替换成convertPoint:toView:(view为nil)
convertSizeToBase:替换成convertSize:toView:
convertRectToBase:替换成convertRect:toView:
convertPointFromBase: 替换成convertPoint:fromView:
convertSizeFromBase: 替换成convertSize:fromView:
convertRectFromBase: 替换成convertRect:fromView:
NSWindow:
convertBaseToScreen:替换成convertRectToScreen:
convertScreenToBase:替换成convertRectFromScreen:
2)图片绘制相关
NSImage的两个方法compositeToPoint:和dissolveToPoint:因为涉及到Base Coordinate System,所以被建议替换成drawAtPoint:fromRect:operation:fraction:。
此外,lockFocus方法也建议用imageWithSize:flipped:drawingHandler:替换。前面提到过,NSImage其实是同时拥有一倍图和两倍图的,会根据目标区域来使用哪一张,而lockFocus其实只处理了一张。
还有,建议使用NSGraphicsContext来处理图像,因为它会自动帮我们处理Scale Factor。
3)Scale Factor相关
因为高分屏Scale Factor的介入,旧Scale Factor相关的需要修改:
a)NSScreen和NSWindow的userSpaceScaleFactor;
b)HIGetScaleFactor方法需用HIWindowGetBackingScaleFactor替换;
c)NSWindow的NSUnscaledWindowMask常量将被抛弃;
一些Trick
如何往NSTextView中添加高清gif图
为了支持高清表情,我们更改了在NSTextView中添加gif图的实现方法,采用了NSFileWrapper的方式,通过NSFileWrapper的setIcon:方法将NSImage设进去。但修改后运行我们发现表情都不会动了。怎么回事?我们跟踪了好一会,途中尝试了几种不同的方法,终于在做了以下处理后使表情运行正常:
- 将表情资源文件的.gif后缀改成.png;
- 高分屏和普通屏分开读取图片,普通屏只读取一倍图,高分屏则采用不使用后缀名的方式读取。
这种做法确实很让人费解,但这确实是我们经过多次尝试后找到的解决办法。之后我们还会继续研究这个问题,希望能找到更好的解决办法。
如何在制作dmg包时让其finder背景也支持retina
Apple没有在高分屏指南的文档中提到任何与dmg相关的内容,也没有为之增加任何新的方法来做这件事。但在其文档中有提到,使用tiffutil来制作复合型的tiff格式图片。在此格式的图片中,同时存储着普通与高清版本图像。事实上经过我们的测试,这种tiff格式图片是可以被用作dmg背景的。具体命令是:
tiffutil -cathidpicheck 普通图 高清图 -out 目标图片名称
需要注意的是:
- DropDMG暂时不支持将tiff作为背景,可以通过修改后缀名为png的方式绕过此限制。
- 用这种方法生成的dmg,在查看时会在左侧有一道奇怪的白边。可能是Apple的实现问题。
工具推荐
高分屏模拟工具
新的MacBook Pro刚出来,货源紧缺,实在不好买到。别担心,Xcode的Graphics Tools可以让我们模拟高分屏。Graphics Tools可以到developer.apple.com下载。 如何模拟高分屏:
- 将Graphics Tools中的Quartz Debug打开;
- 选择UI Resolution菜单;
- 在弹出来的窗口中选择“Enable HiDPI display modes”;
- 注销并重新登录;
- 在系统偏好设置的显示器面板中,选择后面带有HiDPI标志的分辨率。
这样,系统就会模拟高分屏的显示模式。略感不足的是,模拟后的分辨率只有原来的四分之一,操作各种不习惯。没办法,毕竟是一比四的关系啊。
两倍图检查工具
一下子换那么多图,哪些地方的两倍图显示正确,哪些地方还没换,我等肉眼凡胎,检查时难免纰漏。没关系,系统提供了自动标红的功能,帮助我们找出这些地方。
打开方式:在终端中,敲入以下命令
defaults write com.mycompany.myapp CGContextHighlight2xScaledImages YES
( com.mycompany.myapp就是我们需要检查的App名,如果是想检查所有的App,用-g替换 )
打开后,没有换成两倍图的地方,都会被红框标出来,非常方便。
UI实用工具
- Layer Cake,直接从psd生成切图文件,甚至可以从普通psd直接生成高清版本的切图,在为旧软件增加高清支持时尤其方便。
- IconKit,支持生成高清版本的icns文件。
- PaintCode,矢量绘图并直接生成Objective-C代码,自然支持高清,大大减少UI和开发的工作。
Mac平台retina高分屏开发技术分享相关推荐
- MAC 平台retina高分屏开发技术分享
转自:http://guoxiaosi1990.diandian.com/post/2012-07-06/40029975069 版本支持了RETINA,作为国内首个支持RETINA高分屏的MAC O ...
- [分享]错误“应用程序Xcode的这个版本不能与此版本的OS X配合使用”以及Mac源码和IOS开发资料分享
[分享]错误"应用程序Xcode的这个版本不能与此版本的OS X配合使用"以及Mac源码和IOS开发资料分享 安装Xcode时,出现"应用程序Xcode的这个版本不能 ...
- 移动端地图开发技术分享交流会PPT
该文章属于<简书 - 刘小壮>原创,转载请注明: <简书 - 刘小壮> http://www.jianshu.com/p/41179be5893a 本人现就职于国内某地图导航公 ...
- 阿里DataV 2016双十一媒体大屏回顾技术分享
今年在多个部门共同努力下,阿里集团在2015水立方双十一媒体中心立起了一块宽21米,高10米的LED大屏.DataV 数据可视化小组有幸在这么大一块画布上尽兴创作,并且在这个项目中小组第一次尝试使用了 ...
- Workbench二次开发技术分享
之前我发过的关于Workbech二次开发的技术ACT,ACT主要是用来对workbench进行一些横向的开发(诸如workbench现有的载荷类型已经满足不了你的需求,你可以利用ACT技术扩展载荷类型 ...
- Android SDK开发技术分享
最近在工作中负责统一支付平台的SDK开发部分,就此总结下SDK开发的技术点.注意事项.与普通app开发的差别,作为自我总结,也作为公司内部互相学习的分享,希望有Android开发需求或者对Androi ...
- 【Android SDK 开发】Android SDK开发技术分享
原文地址:https://blog.csdn.net/zhangxinjin/article/details/51602577 最近在工作中负责统一支付平台的SDK开发部分,就此总结下SDK开发的技术 ...
- 互联网券商线上开户系统设计与开发技术分享
一.系统背景 国内开户需求 目前目前数据全球化.交易工具全球化.资讯全球化.资产全球化配置已然成为一种势不可挡 的趋势.据港交易所<现货市场交易研究调查 2018>的反应结果,香港以外投资 ...
- 粮草先行——Android折叠屏开发技术点番外篇之运行时变更处理原则
上一篇文章中,我们有提到Activity在屏幕尺寸发生变更时的处理方式,总共有两种: 重启APP以适应屏幕改变: 手动处理数据,避免APP重启. 同样,这两种方式也同时适用于改变屏幕方向.更改系统语言 ...
最新文章
- 优化算法之手推遗传算法(Genetic Algorithm)的详细步骤图解
- 一款实用可行的支付系统,专供互联网企业使用,赶紧收藏了!
- 零基础自学python看什么书-学习Python可以看书籍学习吗?老男孩Python入门课程
- vue 声明周期函数_【Vue】详解Vue生命周期
- [剑指offer]面试题第[48]题[Leetcode][JAVA][第3题][无重复字符的最长字串][滑动窗口][HashSet/Map]
- 面向对象的接口类 以及鸭子类型
- 【Flink】flink sql的并行度怎么单独设置
- Endnote安装出现Internal error 2503解决办法
- AI公开课丨李楠博士带你入门集成学习(第二期)
- python not_刚接触Python,python中not in怎么解释?求解释一下?
- Python代码自动转成C++代码
- 【Word】批量修改Word 图片大小
- 裸机服务器装系统步骤,服务器裸机安装操作系统
- kubeadm,kubevip,containerd部署高可用的kubernetes集群
- 【论文笔记】Question Answering with Subgraph Embeddings
- 路由器局域网IP(内网IP)和外网IP的关系
- Pandas入门基本知识点
- 使用计算机用眼卫生,长期用电脑致眼睛干涩 注意用眼卫生
- 3dmax捕捉的基本操作2
- python-scrapy-MongoDB 爬取链家二手房