一、机型的适配;
坐标:表示屏幕物理尺寸大小,坐标变大了,表示机器屏幕尺寸变大了;
像素:表示屏幕图片的大小,跟坐标之间有个对应关系,比如1:1或1:2等;
ppi:代表屏幕物理大小到图片大小的比例值,如果ppi不变,则坐标和像素的比例不会变;
iPhone、iPhone3/3G机型未采用retina,坐标是320 x 480,屏幕像素320 x 480 ,他们一一对应,1:1关系。即一个坐标对应1个像素。
机器采用了retina屏幕,坐标是320 x 480,屏幕像素640 x 960,他们之间是1:2关系。即一个坐标对应2个像素。
机器采用了retina屏幕,坐标是320 x 568,屏幕像素640 x 1136,他们之间关系式1:2关系。即一个坐标对应2个像素。
机器采用了retina屏幕,坐标是375, 667,屏幕像素750 x 1334,他们之间关系式1:2关系。即一个坐标对应2个像素.
机器采用了retina屏幕,坐标是414, 736,屏幕像素1080 x 1920,他们之间关系式1:2.6关系。即一个坐标对应2.6个像素.
在iPhone 4s之后,不同机型,屏幕大小坐标不变,跟实际图片大小比例不是1:1就是1:2关系。因为坐标不变,所以在开发中可以使用绝对定位,确定每个视图位置,同时提供俩套图片,~.png和~@2x.png,系统根据机器的分辨率自动决定使用哪张图片。
iPhone 5/5s/5c之后,因为屏幕大小坐标已变,高度增加568 - 480 = 88个点,再使用绝对定位的方式,会导致程序高度不够,如果程序未做适配,系统会将多出来的88个点将会将会被自动均分为上下两部分,使得上下出现黑边。对应不同机型,屏幕坐标大小改变了,不能再绝对定位了,为了解决这个问题,ios出现了一种新技术:AutoLayout。AutoLayout可以解决不同机型,屏幕大小的变化,至于图片的适配,因为5/5s/5c,坐标:像素 = 1:2,所以直接使用@2x.png图片就行。 至于@2x图片大小,是按照640 x 960 还是 640 x 1136 的大小,一个是拉伸效果,一个是压缩效果,因为比例差不多,推荐使用大图的。
iPhone 6之后,因为屏幕大小坐标已变,宽、高都增大,但是宽、高比例不变,类似之前的处理方式,使用AutoLayout自动适配,坐标:像素
= 1:2,使用@2x.png图片。
综合之前的,@2x图片可以按照750 x 1334规格来
iPhone 6 plus,类似之前使用AutoLayout,在使用图片的时候,因为 坐标:像素 = 1:2.6,理论上使用@2.6x.png图片即可,但是这不是整数,实际使用很不方便,而@2x 和 @3x 都不太行得通,怎么办?
引用一段文字说的很好:
“不是现有的屏幕物理分辨率明显超过了 @2x 但还达不到 @3x 的水平么?那我们歪打正着一个满足 @3x 的屏幕总可以吧?
对的,歪打正着。
程序在 iPhone 6 Plus 上运行的时候,iOS 会骗它说,你运行在一个超大的 @3x Retina 显示屏上,物理分辨率高达 1242 x 2208,逻辑分辨率是 414 x 736,两者都比 iPhone 6 要大。然后作为设计师和开发人员,也跟着一起歪打正着。设计师画图的时候要把屏幕当成 1242 x 2208 来画图(而且要提供@3x的高清图),开发人员也按照 414 x 736 的逻辑分辨率来写程序。
但借来的总要还的。等咱们歪歪结束了以后,iOS 拿到这个假大的 UI 绘制结果,实时地再缩小到实际的 1080 x 1920 分辨率(系统通过某种算法)。于是,用户在 iPhone 6 Plus 的屏幕上看到的永远是被缩小了的图像:
这么做使得设计和开发的过程大大简化,且最后的实际缩放系数 @2.62x 非常接近理想的 @2.46x,使得同样的素材在真机上看起来尺寸也非常合理。
(1)根据屏幕的宽和高写相关的frame
在新特性界面中,根据:[UIScreen mainScreen].bounds.size.height.来判断用户的屏幕长度,来判断时3.5寸,4寸,4.7寸,5.5寸,以此来设置新特性中图片选用哪套。
常用写法:
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
CGFloat btnW =kScreenWidth* 1/4;
(2)存代码实现AutoLayout,一般使用第三方封装好的Masonry
(3)StoryBoard的AutoLayout,这个我在项目中使用不是太多,但是收集一下网址,大家可以参照学习哦!
iOS AutoLayout与AutoSizing:自动布局
不同机型适配可看成两部分,一是屏幕大小适配(坐标),一是像素适配;前者根据不同的机型大小,视图大小自动适应(AutoLayout);后者根据机型的分辨率和坐标比率,提供合适@xx图片;
目前4s、5/5s/5c、6的适配,使用图片部分,都是使用@2x的图片,在不同的机器上肯定会有一定的拉伸、缩小,目前没看到什么好的解决方案,推荐图片按大图标准做;
趋势:机器屏幕的大小可能会越来越多,绝对定位的方式肯定不行,使用AutoLayout,自动适配屏幕大小,类似网页的思想来设计界面;
趋势:xcode 6中已经可以使用矢量图了,可以使用矢量图,避免各种规格图片;
对于设计师:
(1)非矢量素材,就可以做尺寸最大的,之后再进行缩小。比如你需要兼容3x的屏幕,就直接做最高那种图片。因为之后几种机型长宽比都是9:16,可以直接拉伸。
(2)已有非矢量素材,直接拉伸放大到@3x。
(3)而当使用Flash之类的矢量工具来做素材的时候,应该直接做点那个尺寸。比如44 x 66个点的按钮。就建立一个44 x 66的场景。之后再导出成2倍图,3倍图,因为矢量放大不失真。不要建立一个3x的场景,导出成大图片,再进行缩小,这样就容易失真。
在Info.plist的source code中添加一段代码即可:
[objc]view plaincopy
NSAppTransportSecurity
NSAllowsArbitraryLoads
Bitcode支持watchOS,如果在程序中Bitcode开关是打开的状态,那么第三方库必须支持Bitcode,但是好多第三方库不支持Bitcode,因此在Xcode7会报如下错误:
UMengFeedback_SDK_2.1/libUMFeedback.a(UMChatTableViewCell.o)'doesnot
contain bitcode. You must rebuild it with bitcode enabled
(XcodesettingENABLE_BITCODE), obtain an updated library from the vendor,
or disablebitcodefor this target. for architecture arm64
第一种:使第三方库支持Bitcode(当然这个我们不容易控制,所以这个方案一般不采用);
实际上,在Xcode 7中,我们新建一个iOS程序时,Bitcode选项默认是设置为YES的。我们可以在”BuildSettings”->”Enable
Bitcode”选项中看到这个设置。不过,我们现在需要考虑的是三个平台:iOS,Mac
OS,watchOS;
对于iOS,Bitcode是可选的;对于watchOS,Bitcode是必须的;而Mac
OS是不支持Bitcode。
如果我们开启了Bitcode,在提交程序到AppStore时,会看到有Bitcode的选项
一般应用中都会集成第三方分享,登陆,以及支付,所以需要将三方的相关内容加入到相关的白名单中,可以直接修改plist文件中的代码:
CFBundleURLTypes
CFBundleURLSchemes
testA
也可以直接通过如下方式添加:
4.代码创建UITableView无法隐藏cell的分割线;以及reloadData刷新失效;
解决方法是将设置分割线隐藏的方法self.tableView.separatorStyle
= UITableViewCellSeparatorStyleNone;写在-layoutSubviews中:
-(void)layoutSubviews{ [superlayoutSubviews]; self.tableView.separatorStyle= UITableViewCellSeparatorStyleNone;}
现象:[tableView reloadData]无效,有一行 cell 明明改变了但是刷新不出来。
感觉可能是这个方法和某种新加的特性冲突了,猜测可能是reloadData的操作被推迟到下一个RunLoop执行最终失效。
解决的方法是,注释[tableView reloadData],改用局部刷新:
[self.tableViewreloadSections:[NSIndexSetindexSetWithIndex:0]withRowAnimation:UITableViewRowAnimationNone];
这两个推测均属 Xcode7 的bug,将来 Apple 肯定会修复。
【项目中关于iOS9的适配暂时鄙人遇到这么多,如果你还想了解更多详情,请参照如下教程:iOS9适配系列教程】。
说完iOS9的适配我们来了解一下iOS的一些适配的相关内容(iOS8的适配没有像iOS9那样火爆,就如网络请求一样,如果你不适配iOS9是请求不到数据的,可以说我们是被逼着往前跑的),项目中涉及到的iOS8的适配有如下内容:
1.
[objc]view plaincopy
#ifdef IS_IOS8
@property(nonatomic,strong)UIAlertController*alertC;///ios8的提醒框
#endif
2.
[objc]view plaincopy
/**
消息推送
**/
- (void) msgPush
{
//推送的形式:标记,声音,提示
if(IS_IOS8) {
//1.创建消息上面要添加的动作(按钮的形式显示出来)
UIMutableUserNotificationAction*action = [[UIMutableUserNotificationActionalloc]init];
action.identifier=@"action";//按钮的标示
action.title=@"Accept";//按钮的标题
action.activationMode= UIUserNotificationActivationModeForeground;//当点击的时候启动程序
// action.authenticationRequired = YES;
// action.destructive = YES;
UIMutableUserNotificationAction*action2= [[UIMutableUserNotificationActionalloc]init];
action2.identifier=@"action2";
action2.title=@"Reject";
action2.activationMode= UIUserNotificationActivationModeBackground;//当点击的时候不启动程序,在后台处理
action.authenticationRequired=YES;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略;
action.destructive=YES;
//2.创建动作(按钮)的类别集合
UIMutableUserNotificationCategory*categorys = [[UIMutableUserNotificationCategoryalloc]init];
categorys.identifier=@"alert";//这组动作的唯一标示,推送通知的时候也是根据这个来区分
[categoryssetActions:@[action,action2]forContext:(UIUserNotificationActionContextMinimal)];
//3.创建UIUserNotificationSettings,并设置消息的显示类类型
UIUserNotificationSettings*notiSettings = [UIUserNotificationSettingssettingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIRemoteNotificationTypeSound)categories:[NSSetsetWithObjects:categorys,nilnil]];
[[UIApplicationsharedApplication]registerUserNotificationSettings:notiSettings];
}else{
[[UIApplicationsharedApplication]registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert];
}
}