您的位置:首页 > 移动开发 > IOS开发

IOS 适配的几种模式

2016-05-24 14:14 369 查看
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 ([[UIDevice currentDevice] 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个文件夹,鼠标拖曳到相应的栏位即可。

     具体参数见:http://www.cocoachina.com/bbs/read.php?tid=229352&page=1

三、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模拟器自动生成的截图,截图命名中有汉字。把截图用简短的英文重命名即可。

六、上传更新版本的app
出现如下问题:


原因:
工程中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应用安装界面。不过经过测试似乎该功能目前还不够完善。

IOS7
iOS7最大的变化莫过于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 Framework 

Store Kit在内购方面采用了新的订单系统,这将可以实现对订单的本机验证。这是一次对应内购破解和有可能验证失败导致内购失败的更新,苹果希望藉此减少内购的 实现流程,减少出错,同时遏制内购破解泛滥。前者可能没有问题,但是后者的话,因为objc的动态特性,决定了只要有越狱存在,内购破解也是早晚的事情。 不过这一点确实方便了没有能力架设验证服务器的小开发者,这方面来说还是很好的。 

最后 

当然还有一些其他小改动,包括MessageUI里添加了附件按钮,Xcode开始支持模块了等等。完整的iOS7新特性列表可以在这里找到(暂时 应该也需要开发者账号)。最后一个好消息是,苹果放慢了废弃API的速度,这个版本并没有特别重要的API被标为Deprecated,Cheers。 

原文出自【比特网】,转载请保留原文链接:http://net.chinabyte.com/265/12700765.shtml

3.XCODE SDK的适配

Xcode 6 引入了设计和构建软件的崭新方式。Swift 是一种面向 Cocoa 和 Cocoa Touch 的创新编程语言,与 Xcode 工具相结合后,可以让编程变得轻松愉悦。这一生动体验渗透到了 Xcode 6 的方方面面。Interface Builder 的实时渲染功能,能将你手动编写的 UI 代码显示在设计画布中,并即时反映你在代码中输入的变化。全新的视图调试器将所有 UI 图层迸发为 3D 视觉化呈现,让你轻松了解界面的构成方式,识别重叠或截断的视图。观看“Xcode
6 的新特性”视频 
  
Swift
Xcode 6 对 Swift 有着全面深入的支持。你可以利用 100% Swift 代码创建全新的 app,或者将新的 Swift 代码或框架添加到现有的 app 中,还可查看用 Swift 和/或 Objective-C 语言编写的文档。“跳转至定义”或“快速打开”等所有常见的可供性同样适用于 Swift,甚至还可用 Swift 语法显示 Objective-C 标头定义。 
详细了解 Swift 编程语言 
  
Playground
尽管 Swift 编译为高度优化的原生代码,但 Playground 可以实现脚本语言的交互式体验。键入一行代码,结果便会立即显现。如果你的代码运行一个循环,可将该行代码添加到时间轴辅助编辑器中,观察其进度。以图形方式显示变量,绘制视图时检查每一个步骤,或者观看 SpriteKit 动画场景。在 Playground 中优化好代码后,即可将它移到你的项目中。Playground 文档包括你可以在 Playground
中打开的教程,其中包含可供试验的交互式工作表。 
  
命令行
Xcode 调试器包含 Swift 语言的交互式版本,它称为 REPL (Read-Eval-Print-Loop)。使用 Swift 语法来评估你的现有 app 并与之交互,或者在脚本式环境中编写新的代码。REPL 既可在 Xcode 控制台的 LLDB 中使用,也可通过“终端”调用。 
  
实时渲染
Interface Builder 现可在设计时显示你的自定义对象,就如它们在你的 app 运行时的那样。当你更新自定义视图的代码时,Interface Builder 设计画布可以自动更新为新的外观,无需执行生成和运行。你可以利用 API 添加属性到 IB 检查器中,为你的视图快速更改设计时间,甚至还可以使用示例数据预填充视图,以便对界面有更加精确的了解。 
  
适用于 iOS 的 Storyboard 支持 UIKit 尺寸类,因此你可以开发一个可在任何 iOS 设备上正确运作的通用 Storyboard。为特定设备尺寸或方向挑选特有的行为,同时使界面的大部分元素保持一致、易于维护。Interface Builder 可以在你设计界面时预览任何设备与方向的组合。 
  
视图调试
调试 app 的 UI 现在非常简单,只需点按一下就能将暂停的 app UI 迸发为各个图层构成的 3D 渲染,并在视图堆栈中进行查看。轻松发现视图可能被截断或隐藏的原因,并在检查器中检查和调试各种限制和其他属性。若要修复问题,选择一个视图即可快速跳转到相关的代码。 
  
Xcode 6 还包含其他新的调试工具,如用于监控 I/O 使用量的调试仪表和功能增强的 iCloud 仪表等。调试导航器甚至还能显示更多有用的信息,如记录的堆栈帧和队列中的块等。 

性能测试
XCTest 框架现已扩展为支持性能测试,而且已完全集成到 Xcode 和 Xcode Server 中。Xcode 将运行性能测试,并让你定义基准性能标准。随后的每一项测试将比较性能,显示随时间的变化,并提醒你代码执行可能带来的性能骤降。性能测试已紧密集成到 Xcode 的全新日志 UI 中,该 UI 可以在测试结果变化时清楚地显示出来,在你监控 app 的质量时提醒你性能或功能下降。 
  
各种工具的外观和工作方式更像是 Xcode。所记录数据的轨迹被赋予更多空间,并在统一的检查器区域中管理有关数据收集与查看方式的配置。工具甚至可以描述 XCTest。 
  
更多功能
  
适用于 OS X 的 Storyboard
Storyboard 现已加入到 OS X 中,其充分利用了 AppKit 中的 View Controller API。快速衔接多个视图,定义包含关系和动画,而不必编写代码。适用于 OS X 的 Storyboard 提倡使用遵循 Mac 标准的界面,以使 app 的操作方式符合用户的期望。 
  
扩展和框架
iOS 开发者现在可以创建动态框架,就如在 OS X 上一样。框架是一种代码和资源的集合,对功能进行封装,这项特性在多个项目中很有价值。框架与扩展相辅相成,两者共享的逻辑可由主 app 和捆绑扩展使用。 
  
游戏构建
Xcode 包含一个 SpriteKit 关卡设计器 SceneKit Support,支持粒子编辑器中的新特性。这让创建 iOS 版和 OS X 版游戏变得前所未有的简单。 
  
本地化
Xcode 6 中的本地化现已进行了彻底升级。基础 .strings 文件现在会从你的代码自动生成。通过 Preview Assistant 查看你的 app 在不同语言中的外观,或者使用 iOS Simulator 模拟在其他语言环境中启动你的 app。当内容准备就绪时,Xcode 可以轻松导出和导入业界通用的 .XLIFF 格式。 
  
Xcode Server
在 OS X Server 上运行的 Bot 支持的触发器可根据规则运行自定义脚本,还有更多选项可用于设置运行集成的间隔。此外,Bot 可以通过分组来共享配置。iOS Simulator 配置使得创建独特测试情景变得轻而易举,尤其是通过 Xcode Server 运行时

参考:
xcode版本演化

4.UI布局方式

绝对布局和相对布局

纯代码和xib和storyboard

autosizing

对于IOS的app开发者来说,不会像Android开发者一样为很多的屏幕尺寸来做界面适配,因此硬编码的坐标也能工作良好,但是从设计模式上来说这不是好的做法。而且也还有一些问题,如iPhone5的适配,横竖屏的切换等。或许你可以做两套UI方案来做适配,但是这样增加重复工作量,而且不够高端,万一有出新的屏幕大小了呢。哲理就将介绍IOS中的两大自动布局利器:
Autoresizing
 和 
Autolayout

autoresizing是UIView的属性,一直都有,使用简单,但是没有autolayout强大。autolayout是IOS6以后的新技术,更加强大。本文主要介绍
Autoresizing
的特性和用法。


1. Autoresizing特性

UIView
autoresizesSubviews
YES
时,(默认是YES),
那么在其中的子view会根据它自身的
autoresizingMask
属性来自动适应其与
superView
之间的位置和大小。

autoresizingMask
是一个枚举类型, 默认是
UIViewAutoresizingNone
,
也就是不会autoresize:

<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>
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 };

这个枚举类型,使用了 
1 << n
 这样的写法来定义,代表了它可以复选。如果你不明白为什么,可以复习下“位运算”。
那么这些值分别代表什么意思呢?

其实如何理解这几个值很简单,那就是从xib里面看。 我们在一个xib文件中,取消勾选
autolayout
,(默认使用autolayout时,autoresizing看不到)。那么我们可以在布局那一栏看到如何设置
autoresizing
.



上图说明了在xib中设置的这些线条和实际属性对应的关系,这其中需要注意的是,其中4个margin虚线才代表设置了该值,而width和height是实线代表设置了该值,不能想当然的理解。

这些项分别代表:

autoresizingMask是子视图的左、右、上、下边距以及宽度和高度相对于父视图按比例变化,例如:

UIViewAutoresizingNone 不自动调整。

UIViewAutoresizingFlexibleLeftMargin 自动按比例调整与superView左边的距离,且与superView右边的距离不变。

UIViewAutoresizingFlexibleRightMargin 自动按比例调整与superView的右边距离,且与superView左边的距离不变。

UIViewAutoresizingFlexibleTopMargin  自动按比例调整与superView的顶部距离,且与superView底部的距离不变。

UIViewAutoresizingFlexibleBottomMargin 自动按比例调整与superView的底部距离,且与superView顶部的距离不变。

UIViewAutoresizingFlexibleWidth 自动按比例调整宽度。

UIViewAutoresizingFlexibleHeight 自动按比例调整高度。

UILabel*    label = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 40)];

[label setAutoresizingMask: UIViewAutoresizingNone];  控件相对于父视图坐标值不变   

CGRectMake(50, 100, 200, 40) 

UIViewAutoresizingFlexibleWidth:控件的宽度随着父视图的宽度按比例改变    例如 

label宽度为 100     屏幕的宽度为320          当屏幕宽度为480时      label宽度  变为  100*480/320 

以上这些都较易理解, 但是
autoresizing
还有一些组合场景。那就是组合使用的场景。
autoresizingMask说明xib预览效果
Noneview的frame不会随superview的改变而改变(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)
TopMargin | BottomMarginview与其superView的上边距和下边距的比例维持不变
LeftMargin | RightMarginview与其superView的左边距和右边距的比例维持不变(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)
LeftMargin | RightMargin | TopMargin | BottomMarginview与其superView的上下左右边距的比例维持不变
LeftMargin | Widthview与其superView的右边距的比例维持不变, 左边距和width按比例调整(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)
LeftMargin | Width | RightMargin左边距、右边距、宽按比例调整,(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)垂直方向是同样效果,故不列举
Width | Height自动调整view的宽和高,保证上下左右边距不变。如把tableView设置为此属性,那么无论viewController的view是多大,都能自动铺满
上面并未列举所有组合场景,但是已经足够我们理解 
autoresizing
 了。


2. 小结

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主视图右下角的 
 按钮,即可添加格外的约束条件。可视化的添加不仅很方便直观,而且基本不会出错,是优先推荐的添加约束的方式。但是有时候只靠IB是无法完成某些约束的添加的(比如跨view
hierarchy的约束),有时候IB添加的约束不能满足要求,这时就需要使用约束的API进行补充。


手动使用API添加约束


创建

iOS6中新加入了一个类:NSLayoutConstraint,一个形如这样的约束
item1.attribute = multiplier ⨉ item2.attribute + constant
对应的代码为

[csharp]  view
plain copy

1   [NSLayoutConstraint constraintWithItem:button  

2                                attribute:NSLayoutAttributeBottom  

3                                relatedBy:NSLayoutRelationEqual  

4                                   toItem:superview  

5                                attribute:NSLayoutAttributeBottom  

6                               multiplier:1.0  

7                                 constant:-padding]  

这对应的约束是“button的底部(y) = superview的底部 -10”。


添加

在创建约束之后,需要将其添加到作用的view上。UIView(当然NSView也一样)加入了一个新的实例方法:
-(void)addConstraint:(NSLayoutConstraint *)constraint;
用来将约束添加到view。在添加时唯一要注意的是添加的目标view要遵循以下规则:
对于两个同层级view之间的约束关系,添加到他们的父view上

对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上

对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上


刷新

可以通过-setNeedsUpdateConstraints和-layoutIfNeeded两个方法来刷新约束的改变,使UIView重新布局。这和CoreGraphic的-setNeedsDisplay一套东西是一样的~


Visual Format Language 可视格式语言

UIKit团队这次相当有爱,估计他们自己也觉得新加约束的API名字太长了,因此他们发明了一种新的方式来描述约束条件,十分有趣。这种语言是对视觉描述的一种抽象,大概过程看起来是这样的:accept按钮在cancel按钮右侧默认间距处

 

 

 

最后使用VFL(Visual Format Language)描述变成这样:

[csharp]  view
plain copy

1   [NSLayoutConstraint constraintsWithVisualFormat:@\\"[cancelButton]-[acceptButton]\\"  

2                                           options:0  

3                                           metrics:nil  

4                                             views:viewsDictionary];  

其中viewsDictionary是绑定了view的名字和对象的字典,对于这个例子可以用以下方法得到对应的字典:

[csharp]  view
plain copy

1   UIButton *cancelButton = ...  

2   UIButton *acceptButton = ...  

3   viewsDictionary = NSDictionaryOfVariableBindings(cancelButton,acceptButton);  

生成的字典为
{ acceptButton = ""; cancelButton = ""; }

当然,不嫌累的话自己手写也未尝不可。现在字典啊数组啊写法相对简化了很多了,因此也不复杂。关于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
plain copy

1   [UIView animateWithDuration:0.5 animations:^{  

2       [view layoutIfNeeded];  

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

- (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];
}

在两个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
编辑效果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: