1.尺寸适配
1.原因 iOS7中所有导航栏都为半透明,导航栏(height=44)和状态栏(height=20)不再单独占用高度,即View的(0,0)坐标是从屏幕左上角开始的;而在iOS7之前的系统中,导航栏和状态栏单独占用高度,即View的(0,0)的坐标从导航栏下面开始的。
解决方案:
1> 修改window的frame坐标
这个思路是在iOS7系统里面把windows下拉20个pixel,这样可以让开status bar的位置,于是一切都恢复了正常。
好处是不用每个viewController来逐个修改,一般在AppDelegate.m一个文件里面修改即可。坏处是现实比想象的残酷,看起来简单方便的方法总有各种各样的问题,网上这样做的也各种吐槽,多次努力没结果后我也放弃了继续钻研。
2>. 手动修改坐标
这个方法对于不使用XIB文件的学院派极客是唯一的方法,也没有任何问题,就是工作量大。另外,对于使用IB来辅助做UI的应用来说就不太适合了。
3> 修改Delta值
作为苹果公司来说,推出iOS7时显然可以预计到这样的困境,它也确实给大家提供了解决方案。这个方案是苹果在官方文档里面介绍过的方案。
首先是选择需要适配的IB文件,把Interface Builder Document里面的View as选择成iOS 6.1 and Earlier。
这样在IB里面各个控件都会变成iOS6的样式,但此时在iOS7上运行系统仍然会用iOS7的控件来显示,坐标也仍然不正确——貌似一点作用都没有。恩,这只是第一步,不用急,再做一步就可以实现适配了!
修改DeltaY的值,修改成什么值是根据你的实际情况定的,我这里显然就是status bar的高度,20个pixel。
2.如果使用设置frame ,bounds,里面的尺寸最好使用相对坐标,因为在不同屏幕的手机,如果使用绝对的坐标,在某些手机看来,位置大小就不会那么协调,最简单的是定义一个宏,WIDTH为屏幕宽度,HEIGHT是屏幕宽度
2,IOS版本差异
判断版本号,在高版本的手机上运行低版本的方法,容易过期,过期与否,看官方API
使用高版本好的API,必须加上版本判断,当时低版本的手机时,应该有相应同等功能的API
一、ios7及之前版本****,universal程序准备3套资源:普清(320×480)、高清(1136×768)、ipadhd(2048×1536)。其中,iPhone 4、iphone5、ipad普清(1024×768)使用同一套资源。即背景图使用1136×768,资源图完全相同,针对ipad,使用如下代码:
if([[UIDevicecurrentDevice]userInterfaceIdiom] ==UIUserInterfaceIdiomPad) {//只针对ipad使用该资源
[[CCFileUtils sharedFileUtils]setiPadSuffix:@"-hd"];//ipad使用-hd资源
}
二、针对ios8的适配
主要是Icon和launch image的操作。
在xcode工程中,command + N,——> iOS——》resource——》Asset Catalog。新建这样一个文件。
然后,在这个新建的xcassets文件中,在其左侧栏右键,点击new app icon会产生一个APPIcon文件夹;new launch image,会新建1个LaunchImage文件夹。
这2个文件夹内就是你所需要提供的icon和launch image了。把你做好的icon和launch image放进这2个文件夹,鼠标拖曳到相应的栏位即可。
三、iphone6、iPhone6 plus的资源使用
1、iPhone6的图片资源使用同iPhone5、iPhone4,坐标调整最好使用autolayout.
-hd高清资源的背景图统一调整为:1334×768,iPhone4、5、6以及非Retina的ipad都用这种尺寸的背景图。其余-hd的assets图片资源不变,继续沿用即可。
2、iPhone6 plus图片资源使用ipadhd的资源。
具体操作:(1)在CCCConfiguration.m中,找到如下方法:-(NSInteger) runningDevice。
在此方法中找到这一行:ret = isiPhone5 ? CCDeviceiPhone5 : CCDeviceiPhone;
在这一行之下,if条件之外另起一行,写入:
if ([UIScreen mainScreen].scale == 3.0f) { //iPhone6 plus的特征
ret = CCDeviceiPhoneRetinaDisplay;
}//end if
这几行代码可以让iPhone6 plus使用“-hd”高清资源。
(2)在appdelegate.m中,applicationdidfinishlaunching中,加入:
if (DEVICE_IS_IPHONE6Plus) {
if((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) && ([CCDirector sharedDirector].contentScaleFactor == 3))
{
[CCDirector sharedDirector].contentScaleFactor = ([CCDirector sharedDirector].viewSizeInPixels.width/1024);
}
[[CCFileUtils sharedFileUtils]setiPhoneRetinaDisplaySuffix:@"-ipadhd"];//iphone6 plus使用-ipadhd资源
}
(3)自行调节坐标,以适应iPhone6 plus就可以了。
四、图标icon上又出现了玻璃高光
在工程中选择包含icon和launch image的images.xcassets文件夹,选择Appicon,打开右侧边栏,勾选“iOS icon is pre-rendered”即可,如下:
五、更新版本在iTunesconnect中上传截图,规格尺寸都对,就是上传失败,出现如下提示:
One or more screenshots are in the wrong size. For more information, see the Developer Guide.
原因:上传的是ios模拟器自动生成的截图,截图命名中有汉字。把截图用简短的英文重命名即可。
原因:工程中asset catalog里面,APPIcon中有个carplay图标是120×120的,这个图标不应该加上,将其删除,再次上传就ok了。
下面那个黄色警告可以无视。
IOS8
此次苹果在2014 WWDC开发者大会上发布了全新一代操作系统iOS8。据了解,此次iOS8操作系统虽然和iOS7区别不打,但是苹果注重的是内在,iOS8添加了众多新功能。本文小编先为大家带来苹果iOS8全部新功能详细介绍 16大新功能。
苹果的输入法一直被人诟病,而倒了iOS8苹果终于开放第三方输入法了。喜大普奔的更新!苹果自己的汉字输入法也加入了快速联想功能,输入更迅速。
iMessage可发送语音和视频
干掉微信的节奏?iMessage可以发送语音消息和视频了,而且体验与微信非常类似。
二、通知中心的革新
在锁屏状态下,用户可以直接回复短信。
三、HealthKit健康平台
第三方健康App应用可以通过过此平台来管理心率、运动、饮食等健康数据。
四、Family Sharing家庭分享
一个人买的应用或歌曲,可以分享最多6名亲属使用,同时它还能控制儿童购买应用。
五、改进Siri
Siri更加智能,并且增强了汽车内Siri语音的体验。
六、针对中国的优化
iOS 8针对中国市场进行了特殊优化,比如准确的中文导航和农历等。
七、改进Spotlight搜索
Spotlight不再只是本地搜索,可以搜索互联网内容和应用内容
八、改进多任务界面
多任务切换界面上方加入最近联系人
九、强大的照片编辑功能
Mac、iOS设备可以同步进行图片编辑,可以调整照片的曝光度、对比度、亮度等参数。更加强大
十、TouchID向第三方开放
第三方应用可以使用TouchID接口,意味着未来的很多应用都可以用指纹识别功能了。
十一、HomeKit智能家居功能
苹果向智能家居开放的API,比如未来通过这个API可以实现iPhone控制门锁,控制家庭灯光和电器开关等。
十二、相机对焦时可以自由调节进光量
iOS8不仅为照片的后期处理加入了强大编辑功能,内置相机同样增加了一项不可忽视的功能——自由调节进光量,在拍摄中,触摸屏幕对好焦点后,会在对焦框旁边出现进光量调节轴,能够自由增加或降低拍摄的曝光量,再也不必因为光的问题频繁找焦点测光了。
十三、Safari新增DuckDuckGo搜索引擎
DuckDuckGo是来自于美国的一家小型搜索引擎商,其最大的特点是严格保护用户的隐私,承诺不记录不监控用户的搜索内容,搜索内容也更加的精准。相信国内用户是不关心它的,不过有多一个好选择也不错。[4]
十四、监测每款应用的耗电量
iOS8还有一个隐藏较深的功能,在设置中打开电池用量菜单,用户会发现近期使用过的APP的耗电百分比都在里面,一目了然。经过这样的监测,的确是相机最耗电!
十五、盲文键盘
iOS8终于新增了盲文键盘。对于盲人来说,这真的是个福音,这也将会对他们的生活产生巨大影响。[4]
十六、智能快捷按钮
iOS8设备会根据位置,自动在锁屏界面左下角显示相关应用的快捷启动按钮。在iOS8Beta1测试版中,苹果利用iBeacon技术将基于地理位置的应用通知推送到用户iPhone或iPad的锁屏界面上,这些通知图标位于锁屏界面左下方,用户可以按住这个小图标向上滑动解锁设备打开该应用。[5]
比如当用户拿着更新至iOS8的手机到星巴克咖啡店时,星巴克的APP就会出现在锁屏的左下角(与相机快捷键相对应),用户按住它向上滑动就可以直接启动APP,与锁屏启动相机APP一致。此外,即使用户没有安装某个应用,在特定地点时,iOS 8也会向用户推荐应用,只是打开后会进入App Store应用安装界面。不过经过测试似乎该功能目前还不够完善。
IOS7iOS7最大的变化莫过于UI设计,也许你会说UI设计“这是设计师大大们应该关注的事情,不关开发者的事,我们只需要替换图片就行了”。那你就错了。 UI的变化必然带来使用习惯和方式的转变,如何运用iOS7的UI,如何是自己的应用更切合新的系统,都是需要考虑的事情。另外值得注意的是,使用 iOS7 SDK(现在只有Xcode5预览版提供)打包的应用在iOS7上运行时将会自动使用iOS7的新界面,所以原有应用可能需要对新界面进行重大调整。具体 的iOS7中所使用的UI元素的人际交互界面文档,可以从这里找到(应该是需要开发者账号才能看)。ios-7-logo简单总结来说,以现在上手体验看来新的UI变化改进有如下几点:1.状态栏,导航栏和应用实际展示内容不再界限:系统自带的应用都不再区分状态栏和navigation bar,而是用统一的颜色力求简洁。这也算是一种趋势。2.BarItem的按钮全部文字化:这点做的相当坚决,所有的导航和工具条按钮都取消了拟物化,原来的文字(比如“Edit”,“Done”之类)改为了简单的文字,原来的图标(比如新建或者删除)也做了简化。3.程序打开加入了动画:从主界面到图标所在位置的一个放大,同时显示应用的载入界面。自己实验了几个现有的AppStore应用在iOS7上的运行情况:1.Pomodoro Do: 这是我自己开发的应用,运行正常,但是因为不是iOS7 SDK打包,所以在UI上使用了之前系统的,问题是导航栏Tint颜色丢失,导致很难看,需要尽快更新。2.Facebook:因为使用了图片自定义导航栏,而没有直接使用系统提供的材质,所以没什么问题。3.面包旅行:直接Crash,无法打开,原因未知。这次UI大改可以说是一次对敏捷开发的检验,原来的应用(特别是拟物化用得比较重的应用)虽然也能运行,但是很多UI自定义的地方需要更改不说,还 容易让用户产生一种“来到了另一个世界”的感觉,同时可以看到也有部分应用无法运行。而对于苹果的封闭系统和只升不降的特性,开发者以及其应用必须要尽快 适应这个新系统,这对于迭代快速,还在继续维护的应用来说会是一个机会。相信谁先能适应新的UI,谁就将在iOS7上占到先机。动态UIKit新增了UIDynamicItem委托,用来为UIView制定动态行为,当然其他任何对象都能通过实现这组接口来定义动态行为,只不过在UIKit中可 能应用最多。所谓动态行为,是指将现实世界的行为或者特性引入到UI中,比如重力等。通过实现UIDynamicItem,UIKit现在支持如下行为: * UIAttachmentBehavior 连接两个实现了UIDynamicItem的物体(以下简称动态物体),一个物体移动时,另一个跟随移动 * UICollisionBehavior 指定边界,使两个动态物体可以进行碰撞 * UIGravityBehavior 顾名思义,为动态物体增加重力模拟 * UIPushBehavior 为动态物体施加持续的力 * UISnapBehavior 为动态物体指定一个附着点,想象一下类似挂一幅画在图钉上的感觉。如果有开发游戏的童鞋可能会觉得这些很多都是做游戏时候的需求,一种box2d之类的2D物理引擎的既视感跃然而出。没错的亲,动态UI,加上之后 要介绍的Sprite Kit,极大的扩展了使用UIKit进行游戏开发的可能性。另外要注意UIDynamicItem不仅适用于UIKit,任何对象都可以实现接口来获得动 态物体的一些特性,所以说用来做一些3D的事情也不是没有可能。如果觉得Cocos2D+box2d这样的组合使用起来不方便的话,现在动态 UIKit+SpriteKit给出了新的选择。游戏方面iOS7 SDK极大加强了直接使用iOS SDK制作和分发游戏的体验,最主要的是引入了专门的游戏制作框架。Sprite Kit Framework这是个人认为iOS7 SDK最大的亮点,也是最重要的部分,iOS SDK终于有自己的精灵系统了。Sprite Kit Framework使用硬件加速的动画系统来表现2D和2.5D的游戏,它提供了制作游戏所需要的大部分的工具,包括图像渲染,动画系统,声音播放以及图 像模拟的物理引擎。可以说这个框架是iOS SDK自带了一个较完备的2D游戏引擎,力图让开发者专注于更高层的实现和内容。和大多数游戏引擎一样,Sprite Kit内的内容都按照场景(Scene)来分开组织,一个场景可以包括贴图对象,视频,形状,粒子效果甚至是CoreImage滤镜等等。相对于现有的 2D引擎来说,由于Sprite Kit是在系统层级进行的优化,渲染时间等都由框架决定,因此应该会有比较高的效率。另外,Xcode还提供了创建粒子系统和贴图Atlas的工具。使用Xcode来管理粒子效果和贴图atlas,可以迅速在Sprite Kit中反应出来。Game Controller Framework为Made-for-iPhone/iPod/iPad (MFi) game controller设计的硬件的对应的框架,可以让用户用来连接和控制专门的游戏硬件。参考WWDC 2013开场视频中开始的赛车演示。现在想到的是,也许这货不仅可以用于游戏…或者苹果之后会扩展其应用,因为使用普及率很高的iPhone作为物联网的 入口,似乎会是很有前途的事情。GameCenter改进GameCenter一直是苹果的败笔…虽然每年都在改进,但是一直没看到大的起色。今年也不例外,都是些小改动,不提也罢。多任务强化经常需要下载新内容的应用现在可以通过设置UIBackgroundModes为fetch来实现后台下载内容了,需要在AppDelegate里实现setMinimumBackgroundFetchInterval:以及application:performFetchWithCompletionHandler:来处理完成的下载,这个为后台运行代码提供了又一种选择。不过考虑到Apple如果继续严格审核的话,可能只有杂志报刊类应用能够取得这个权限吧。另外需要注意开发者仅只能指定一个最小间隔,最后下没下估计就得看系统娘的心情了。同样是后台下载,以前只能推送提醒用户进入应用下载,现在可以接到推送并在后台下载。UIBackgroundModes设为remote-notification,并实现application:didReceiveRemoteNotification:fetchCompletionHandler:为后台下载,开发者必须使用一个新的类NSURLSession,其实就是在NSURLConnection上加了个后台处理,使用类似,API十分简单,不再赘述。AirDrop这个是iOS7的重头新功能,用户可以用它来分享照片,文档,链接,或者其他数据给附近的设备。但是不需要特别的实现,被集成在了标准的 UIActivityViewController里,并没有单独的API提供。数据的话,可以通过实现UIActivityItemSource接口后 进行发送。大概苹果也不愿意看到超出他们控制的文件分享功能吧,毕竟这和iOS设计的初衷不一样。如果你不使用 UIActivityViewController的话,可能是无法在应用里实装AirDrop功能了。地图Apple在继续在地图应用上的探索,MapKit的改进也乏善可陈。我一直相信地图类应用的瓶颈一定在于数据,但是对于数据源的建立并不是一年两年能够完成的。Google在这一块凭借自己的搜索引擎有着得天独厚的优势,苹果还差的很远很远。看看有哪些新东西吧:1.MKMapCamera,可以将一个MKMapCamera对象添加到地图上,在指明位置,角度和方向后将呈现3D的样子…大概可以想象成一个数字版的Google街景..2.MKDirections 获取Apple提供的基于方向的路径,然后可以用来将路径绘制在自己的应用中。这可能对一些小的地图服务提供商产生冲击,但是还是那句话,地图是一个数据 的世界,在拥有完备数据之前,Apple不是Google的对手。这个状况至少会持续好几年(也有可能是永远)。3.MKGeodesicPolyline 创建一个随地球曲率的线,并附加到地图上,完成一些视觉效果。4.MKMapSnapshotter 使用其拍摄基于地图的照片,也许各类签到类应用会用到。5.改变了overlay物件的渲染方式。Inter-App Audio 应用间的音频AudioUnit框架中加入了在同一台设备不同应用之间发送MIDI指令和传送音频的能力。比如在一个应用中使用AudioUnit录音,然后在另一个 应用中打开以处理等。在音源应用中声明一个AURemoteIO实例来标为Inter-App可用,在目标应用中使用新的发现接口来发现并获取音频。 想法很好,也算是在应用内共享迈出了一步,不过我对现在使用AudioUnit这样的低层级框架的应用数量表示不乐观。也许今后会有一些为更高层级设计的 共享API提供给开发者使用。毕竟要从AudioUnit开始处理音频对于大多数开发者来说并不是一件很容易的事情。点对点连接 Peer-to-Peer Connectivity可以看成是AirDrop不能直接使用的补偿,代价是需要自己实现。MultipeerConnectivity框架可以用来发现和连接附近的设备,并传 输数据,而这一切并不需要有网络连接。可以看到Apple逐渐在文件共享方面一步步放开限制,但是当然所有这些都还是被限制在sandbox里的。Store Kit FrameworkStore Kit在内购方面采用了新的订单系统,这将可以实现对订单的本机验证。这是一次对应内购破解和有可能验证失败导致内购失败的更新,苹果希望藉此减少内购的 实现流程,减少出错,同时遏制内购破解泛滥。前者可能没有问题,但是后者的话,因为objc的动态特性,决定了只要有越狱存在,内购破解也是早晚的事情。 不过这一点确实方便了没有能力架设验证服务器的小开发者,这方面来说还是很好的。最后当然还有一些其他小改动,包括MessageUI里添加了附件按钮,Xcode开始支持模块了等等。完整的iOS7新特性列表可以在这里找到(暂时 应该也需要开发者账号)。最后一个好消息是,苹果放慢了废弃API的速度,这个版本并没有特别重要的API被标为Deprecated,Cheers。
3.XCODE SDK的适配
绝对布局和相对布局
纯代码和xib和storyboard
autosizing
对于IOS的app开发者来说,不会像Android开发者一样为很多的屏幕尺寸来做界面适配,因此硬编码的坐标也能工作良好,但是从设计模式上来说这不是好的做法。而且也还有一些问题,如iPhone5的适配,横竖屏的切换等。或许你可以做两套UI方案来做适配,但是这样增加重复工作量,而且不够高端,万一有出新的屏幕大小了呢。哲理就将介绍IOS中的两大自动布局利器:Autoresizing
和Autolayout
。 autoresizing是UIView的属性,一直都有,使用简单,但是没有autolayout强大。autolayout是IOS6以后的新技术,更加强大。本文主要介绍Autoresizing
的特性和用法。
- Autoresizing特性
当UIView
的autoresizesSubviews
是YES
时,(默认是YES), 那么在其中的子view会根据它自身的autoresizingMask
属性来自动适应其与superView
之间的位置和大小。
autoresizingMask
是一个枚举类型, 默认是UIViewAutoresizingNone
, 也就是不会autoresize:
?
1
2
3
4
5
6
7
8
9
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
1
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
2
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
3
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
4
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
5
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
6
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
7
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
8
</span>
<span
class
=
"line-number"
style=
"margin: 0px; padding: 0px;"
9
</span>
?
1
<code
class
=
"objc"
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone =
0
, UIViewAutoresizingFlexibleLeftMargin =
1
<<
0
, UIViewAutoresizingFlexibleWidth =
1
<<
1
, UIViewAutoresizingFlexibleRightMargin =
1
<<
2
, UIViewAutoresizingFlexibleTopMargin =
1
<<
3
, UIViewAutoresizingFlexibleHeight =
1
<<
4
, UIViewAutoresizingFlexibleBottomMargin =
1
<<
5
}; </code>
这个枚举类型,使用了1 << n
这样的写法来定义,代表了它可以复选。如果你不明白为什么,可以复习下“位运算”。 那么这些值分别代表什么意思呢?
其实如何理解这几个值很简单,那就是从xib里面看。 我们在一个xib文件中,取消勾选autolayout
,(默认使用autolayout时,autoresizing看不到)。那么我们可以在布局那一栏看到如何设置autoresizing
.
![](http://upload-images.jianshu.io/upload_images/1663804-2587b26da6a86077.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
上图说明了在xib中设置的这些线条和实际属性对应的关系,这其中需要注意的是,其中4个margin虚线才代表设置了该值,而width和height是实线代表设置了该值,不能想当然的理解。
这些项分别代表:
autoresizingMask是子视图的左、右、上、下边距以及宽度和高度相对于父视图按比例变化,例如:
UIViewAutoresizingNone 不自动调整。
UIViewAutoresizingFlexibleLeftMargin 自动按比例调整与superView左边的距离,且与superView右边的距离不变。
UIViewAutoresizingFlexibleRightMargin 自动按比例调整与superView的右边距离,且与superView左边的距离不变。
UIViewAutoresizingFlexibleTopMargin 自动按比例调整与superView的顶部距离,且与superView底部的距离不变。
UIViewAutoresizingFlexibleBottomMargin自动按比例调整与superView的底部距离,且与superView顶部的距离不变。
UIViewAutoresizingFlexibleWidth自动按比例调整宽度。
UIViewAutoresizingFlexibleHeight自动按比例调整高度。
UILabellabel = [[UILabelalloc]initWithFrame:CGRectMake(50,100,200,40)];
[labelsetAutoresizingMask:UIViewAutoresizingNone]; 控件相对于父视图坐标值不变
CGRectMake(50,100,200,40)UIViewAutoresizingFlexibleWidth:控件的宽度随着父视图的宽度按比例改变 例如label宽度为 100 屏幕的宽度为320 当屏幕宽度为480时 label宽度 变为 100480/320 以上这些都较易理解, 但是autoresizing
还有一些组合场景。那就是组合使用的场景。
autoresizingMask
说明
xib预览效果
None
view的frame不会随superview的改变而改变(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)
![](http://upload-images.jianshu.io/upload_images/1663804-60bd37fb3b7ef304.gif?imageMogr2/auto-orient/strip)
TopMargin | BottomMargin
view与其superView的上边距和下边距的比例维持不变
![](http://upload-images.jianshu.io/upload_images/1663804-783aecc927814a5c.gif?imageMogr2/auto-orient/strip)
LeftMargin | RightMargin
view与其superView的左边距和右边距的比例维持不变(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)
![](http://upload-images.jianshu.io/upload_images/1663804-4bb2d34044c67c41.gif?imageMogr2/auto-orient/strip)
LeftMargin | RightMargin | TopMargin | BottomMargin
view与其superView的上下左右边距的比例维持不变
![](http://upload-images.jianshu.io/upload_images/1663804-2ea0fcf44e4811d3.gif?imageMogr2/auto-orient/strip)
LeftMargin | Width
view与其superView的右边距的比例维持不变, 左边距和width按比例调整(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)
![](http://upload-images.jianshu.io/upload_images/1663804-2347569b4969f7f2.gif?imageMogr2/auto-orient/strip)
LeftMargin | Width | RightMargin
左边距、右边距、宽按比例调整,(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)垂直方向是同样效果,故不列举
![](http://upload-images.jianshu.io/upload_images/1663804-558ba8dddf3cae53.gif?imageMogr2/auto-orient/strip)
Width | Height
自动调整view的宽和高,保证上下左右边距不变。如把tableView设置为此属性,那么无论viewController的view是多大,都能自动铺满
![](http://upload-images.jianshu.io/upload_images/1663804-18540367c32ba0a0.gif?imageMogr2/auto-orient/strip)
上面并未列举所有组合场景,但是已经足够我们理解autoresizing
了。
- 小结
Autoreszing的最常见的实用场景就是iPhone5的兼容了。比如我们想要设置tableView的frame,那我们只需要在初始化设置frame之后将tableView的autoresizingMask设置为UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight
就行了。
另一种比如我们想要一个view一直停留在其superview的最下方,那么我们在初始化设置frame之后只需要将autoresizingMask设置为UIViewAutoresizingFlexibleTopMargin
就可以了。
autorezingMask简单的一个属性,理解它之后可以让很多事情变得简单。
AutoLayout
AutoLayout是什么?
使用一句Apple的官方定义的话AutoLayout是一种基于约束的,描述性的布局系统。Auto Layout Is a Constraint-Based, Descriptive Layout System.
关键词:基于约束 - 和以往定义frame的位置和尺寸不同,AutoLayout的位置确定是以所谓相对位置的约束来定义的,比如x坐标为superView的中心,y坐标为屏幕底部上方10像素等描述性 - 约束的定义和各个view的关系使用接近自然语言或者可视化语言(稍后会提到)的方法来进行描述布局系统 - 即字面意思,用来负责界面的各个元素的位置。 总而言之,AutoLayout为开发者提供了一种不同于传统对于UI元素位置指定的布局方法。以前,不论是在IB里拖放,还是在代码中写,每个UIView都会有自己的frame属性,来定义其在当前视图中的位置和尺寸。使用AutoLayout的话,就变为了使用约束条件来定义view的位置和尺寸。这样的 最大好处是一举解决了不同分辨率和屏幕尺寸下view的适配问题,另外也简化了旋转时view的位置的定义,原来在底部之上10像素居中的view,不论在旋转屏幕或是更换设备(iPad或者iPhone5或者以后可能出现的mini iPad)的时候,始终还在底部之上10像素居中的位置,不会发生变化。总结使用约束条件来描述布局,view的frame会依据这些约束来进行计算Describe the layout with constraints, and frames are calculated automatically.
AutoLayout和Autoresizing Mask的区别
Autoresizing Mask是我们的老朋友了…如果你以前一直是代码写UI的话,你肯定写过UIViewAutoresizingFlexibleWidth之类的枚举;如果你以前用IB比较多的话,一定注意到过每个view的size inspector中都有一个红色线条的Autoresizing的指示器和相应的动画缩放的示意图,这就是Autoresizing Mask。在iOS6之前,关于屏幕旋转的适配和iPhone,iPad屏幕的自动适配,基本都是由Autoresizing Mask来完成的。但是随着大家对iOS app的要求越来越高,以及已经以及今后可能出现的多种屏幕和分辨率的设备来说,Autoresizing Mask显得有些落伍和迟钝了。AutoLayout可以完成所有原来Autoresizing Mask能完成的工作,同时还能够胜任一些原来无法完成的任务,其中包括:AutoLayout可以指定任意两个view的相对位置,而不需要像Autoresizing Mask那样需要两个view在直系的view hierarchy中。AutoLayout不必须指定相等关系的约束,它可以指定非相等约束(大于或者小于等);而Autoresizing Mask所能做的布局只能是相等条件的。AutoLayout可以指定约束的优先级,计算frame时将优先按照满足优先级高的条件进行计算。 总结Autoresizing Mask是AutoLayout的子集,任何可以用Autoresizing Mask完成的工作都可以用AutoLayout完成。AutoLayout还具备一些Autoresizing Mask不具备的优良特性,以帮助我们更方便地构建界面。
AutoLayout基本使用方法
Interface Builder
最简单的使用方法是在IB中直接拖。在IB中任意一个view的File inspector下面,都有Use Autolayout的选择框(没有的同学可以考虑升级一下Xcode了=。=),钩上,然后按照平常那样拖控件就可以了。拖动控件后在左边的view hierarchy栏中会出现Constraints一向,其中就是所有的约束条件。
选中某个约束条件后,在右边的Attributes inspector中可以更改约束的条件,距离值和优先度等:
对于没有自动添加的约束,可以在IB中手动添加。选择需要添加约束的view,点击菜单的Edit->Pin里的需要的选项,或者是点击IB主视图右下角的
创建
iOS6中新加入了一个类:NSLayoutConstraint,一个形如这样的约束item1.attribute = multiplier ? item2.attribute + constant 对应的代码为[csharp]view plaincopy 1[NSLayoutConstraintconstraintWithItem:button
2attribute:NSLayoutAttributeBottom
3relatedBy:NSLayoutRelationEqual
4toItem:superview
5attribute:NSLayoutAttributeBottom
6multiplier:1.0
7constant:-padding]
这对应的约束是“button的底部(y) = superview的底部 -10”。在创建约束之后,需要将其添加到作用的view上。UIView(当然NSView也一样)加入了一个新的实例方法: -(void)addConstraint:(NSLayoutConstraint )constraint; 用来将约束添加到view。在添加时唯一要注意的是添加的目标view要遵循以下规则:对于两个同层级view之间的约束关系,添加到他们的父view上
可以通过-setNeedsUpdateConstraints和-layoutIfNeeded两个方法来刷新约束的改变,使UIView重新布局。这和CoreGraphic的-setNeedsDisplay一套东西是一样的~Visual Format Language 可视格式语言
UIKit团队这次相当有爱,估计他们自己也觉得新加约束的API名字太长了,因此他们发明了一种新的方式来描述约束条件,十分有趣。这种语言是对视觉描述的一种抽象,大概过程看起来是这样的:accept按钮在cancel按钮右侧默认间距处
2options:0
3metrics:nil
4views:viewsDictionary];
其中viewsDictionary是绑定了view的名字和对象的字典,对于这个例子可以用以下方法得到对应的字典:[csharp]view plaincopy 1UIButtoncancelButton=...
2UIButtonacceptButton=...
3viewsDictionary=NSDictionaryOfVariableBindings(cancelButton,acceptButton);
生成的字典为当然,不嫌累的话自己手写也未尝不可。现在字典啊数组啊写法相对简化了很多了,因此也不复杂。关于Objective-C的新语法,可以参考我之前的一篇WWDC 2012笔记:WWDC 2012 Session笔记——405 Modern Objective-C。在view名字后面添加括号以及连接处的数字可以赋予表达式更多意义,以下进行一些举例: [cancelButton(72)]-12-[acceptButton(50)] 取消按钮宽72point,accept按钮宽50point,它们之间间距12point [wideView(>=60@700)] wideView宽度大于等于60point,该约束条件优先级为700(优先级最大值为1000,优先级越高的约束越先被满足) V:[redBox][yellowBox(==redBox)] 竖直布局,先是一个redBox,其下方紧接一个宽度等于redBox宽度的yellowBox H:|-[Find]-[FindNext]-[FindField(>=20)]-| 水平布局,Find距离父view左边缘默认间隔宽度,之后是FindNext距离Find间隔默认宽度;再之后是宽度不小于20的FindField,它和FindNext以及父view右边缘的间距都是默认宽度。(竖线'|‘ 表示superview的边缘)容易出现的错误
因为涉及约束问题,因此约束模型下的所有可能出现的问题这里都会出现,具体来说包括两种:Ambiguous Layout 布局不能确定Unsatisfiable Constraints 无法满足约束 布局不能确定指的是给出的约束条件无法唯一确定一种布局,也即约束条件不足,无法得到唯一的布局结果。这种情况一般添加一些必要的约束或者调整优先级可以解决。无法满足约束的问题来源是有约束条件互相冲突,因此无法同时满足,需要删掉一些约束。两种错误在出现时均会导致布局的不稳定和错误,Ambiguous可以被容忍并且选择一种可行布局呈现在UI上,Unsatisfiable的话会无法得到UI布局并报错。对于不能确定的布局,可以通过调试时暂停程序,在debugger中输入
po [[UIWindow keyWindow] _autolayoutTrace] 来检查是否存在Ambiguous Layout以及存在的位置,来帮助添加条件。另外还有一些检查方法,来查看view的约束和约束状态:[view constraintsAffectingLayoutForOrientation/Axis: NSLayoutConstraintOrientationHorizontal/Vertical][view hasAmbiguousLayout] [view exerciseAmbiguityInLayout]布局动画
动画是UI体验的重要部分,更改布局以后的动画也非常关键。说到动画,Core Animation又立功了..自从CA出现以后,所有的动画效果都非常cheap,在auto layout中情况也和collection view里一样,很简单(可以参考 WWDC 2012 Session笔记——219 Advanced Collection Views and Building Custom Layouts),只需要把layoutIfNeeded放到animation block中即可~[csharp]view plaincopy 1[UIViewanimateWithDuration:0.5animations:^{
2[viewlayoutIfNeeded];
3}];
SizeClass
http://joywii.github.io/blog/2014/09/24/ios8-size-classesde-li-jie-yu-shi-yong/
Size Classes是什么
iOS 8在应用界面的可视化设计上添加了一个新的特性-Size Classes,对于任何设备来说,界面的宽度和高度都只分为两种描述:正常
和紧凑
。这样开发者便可以无视设备具体的尺寸,而是对这两类和它们的组合进行适配。这样不论在设计时还是代码上,我们都可以不再受限于具体的尺寸,而是变成遵循尺寸的视觉感官来进行适配。在Xcode中的具体体现如下图:
但是我们看到图中的宽度和高度都是Any
,Any是什么意思呢?如果weight
设为Any
,height
设置为Regular
,那么在该状态下的界面元素在只要height
为Regular
,无论weight
是Regular
还是Compact
的状态中都会存在。这种关系应该叫做继承关系,具体的四种界面描述与可继承的界面描述如下:
w:Compact h:Compact 继承 (w:Any h:Compact,w:Compact h:Any,w:Any h:Any)
w:Regular h:Compact 继承 (w:Any h:Compact,w:Regular h:Any,w:Any h:Any)
w:Compact h:Regular 继承 (w:Any h:Regular,w:Compact h:Any,w:Any h:Any)
w:Regular h:Regular 继承 (w:Any h:Regular,w:Regular h:Any,w:Any h:Any)我们知道了iOS 8下面设备界面可以描述为4种,但是这么多设备(iPhone4S,iPhone5/5s,iPhone6,iPhone6 Plus,iPad,Apple Watch)具体对应什么描述呢?经过查看官方文档和具体实践得知具体对应关系如下:
iPhone4S,iPhone5/5s,iPhone6竖屏:(w:Compact h:Regular)
横屏:(w:Compact h:Compact)
iPhone6 Plus竖屏:(w:Compact h:Regular)
横屏:(w:Regular h:Compact)
iPad竖屏:(w:Regular h:Regular)
横屏:(w:Regular h:Regular)
Apple Watch(猜测)竖屏:(w:Compact h:Compact)
横屏:(w:Compact h:Compact)Size Classes手写代码
为了表征Size Classes
,Apple在iOS8中引入了一个新的类,UITraitCollection
。这个类封装了像水平和竖直方向的Size Class等信息。iOS8的UIKit中大多数UI的基础类(包括UIScreen,UIWindow,UIViewController和UIView)都实现了UITraitEnvironment
这个接口,通过其中的traitCollection
这个属性,我们可以拿到对应的UITraitCollection
对象,从而得知当前的Size Class,并进一步确定界面的布局。和UIKit中的响应者链正好相反,traitCollection
将会在view hierarchy
中自上而下地进行传递。对于没有指定traitCollection
的UI部件,将使用其父节点的traitCollection
。这在布局包含childViewController
的界面的时候会相当有用。在UITraitEnvironment
这个接口中另一个非常有用的是-traitCollectionDidChange:
。在traitCollection
发生变化时,这个方法将被调用。在实际操作时,我们往往会在ViewController
中重写-traitCollectionDidChange:
或者-willTransitionToTraitCollection:withTransitionCoordinator:
方法(对于ViewController
来说的话,后者也许是更好的选择,因为提供了转场上下文方便进行动画;但是对于普通的View来说就只有前面一个方法了),然后在其中对当前的traitCollection
进行判断,并进行重新布局以及动画。代码看起来大概会是这个样子:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code>- (
void
)willTransitionToTraitCollection:(UITraitCollection *)newCollection
withTransitionCoordinator:(id <uiviewcontrollertransitioncoordinator>)coordinator
{
[
super
willTransitionToTraitCollection:newCollection
withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id <uiviewcontrollertransitioncoordinatorcontext> context)
{
if
(newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
//To Do: modify something for compact vertical size
}
else
{
//To Do: modify something for other vertical size
}
[self.view setNeedsLayout];
} completion:nil];
}</uiviewcontrollertransitioncoordinatorcontext></uiviewcontrollertransitioncoordinator></code>
在两个To Do处,我们要手写代码针对不同的状态做调整。
Size Classes与Interface Builder
Xcode6中Interface Builder
对Size Class
有了很强大的支持,xib中可以开启Size Classes如下图:
在不同的Size Classes
描述下,界面元素可以选择安装还是不安装,具体操作如图:
Size Classes与Image Asset
Xcode6中Image Asset
也支持了Size Class
,也就是说,我们可以对不同的Size Class
指定不同的图片了。在Image Asset
的编辑面板中选择某张图片,Inspector里现在多了一个Width
和Height
的组合,添加我们需要对应的Size Class
,然后把合适的图拖上去,这样在运行时SDK
就将从中挑选对应的Size
的图进行替换了。支持Size Class
的Image Asset
编辑效果如下: