频道栏目
首页 > 程序开发 > 移动开发 > IOS > 正文
IOS 适配的几种模式
2016-05-25 09:17:08         来源:清风飏  
收藏   我要投稿

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”即可,如下:

关于适配ios8、iPhone6、iphone<wbr>plus以及资源优化相关问题
 

 

 

五、更新版本在iTunesconnect中上传截图,规格尺寸都对,就是上传失败,出现如下提示:

One or more screenshots are in the wrong size. For more information, see the Developer Guide.

 

原因:上传的是ios模拟器自动生成的截图,截图命名中有汉字。把截图用简短的英文重命名即可。

 

 

六、上传更新版本的app

出现如下问题:

关于适配ios8、iPhone6、iphone<wbr>plus以及资源优化相关问题
原因:

工程中asset catalog里面,APPIcon中有个carplay图标是120×120的,这个图标不应该加上,将其删除,再次上传就ok了。

 

下面那个黄色警告可以无视。

IOS8

 

此次苹果在2014 WWDC开发者大会上发布了全新一代操作系统iOS8。据了解,此次iOS8操作系统虽然和iOS7区别不打,但是苹果注重的是内在,iOS8添加了众多新功能。本文小编先为大家带来苹果iOS8全部新功能详细介绍 16大新功能。

iOS8怎么升级 iOS8 beta测试版升级教程

一、支持第三方输入法

苹果的输入法一直被人诟病,而倒了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。
 

 

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 运行时

4.UI布局方式

绝对布局和相对布局

纯代码和xib和storyboard

 

autosizing

 

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

1. Autoresizing特性

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

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

1
2
3
4
5
6
7
8
9
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 = [[UILabelalloc]initWithFrame:CGRectMake(50,100,200,40)];

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

CGRectMake(50,100,200,40)

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

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


以上这些都较易理解, 但是autoresizing还有一些组合场景。那就是组合使用的场景。

autoresizingMask 说明 xib预览效果
None view的frame不会随superview的改变而改变(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变) \
TopMargin | BottomMargin view与其superView的上边距和下边距的比例维持不变 \
LeftMargin | RightMargin view与其superView的左边距和右边距的比例维持不变(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变) \
LeftMargin | RightMargin | TopMargin | BottomMargin view与其superView的上下左右边距的比例维持不变 \
LeftMargin | Width view与其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 plaincopy

     

    1. 1[NSLayoutConstraintconstraintWithItem:button
    2. 2attribute:NSLayoutAttributeBottom
    3. 3relatedBy:NSLayoutRelationEqual
    4. 4toItem:superview
    5. 5attribute:NSLayoutAttributeBottom
    6. 6multiplier:1.0
    7. 7constant:-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 plaincopy

 

  1. 1[NSLayoutConstraintconstraintsWithVisualFormat:@\\"[cancelButton]-[acceptButton]\\"
  2. 2options:0
  3. 3metrics:nil
  4. 4views:viewsDictionary];

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

[csharp]view plaincopy

 

  1. 1UIButton*cancelButton=...
  2. 2UIButton*acceptButton=...
  3. 3viewsDictionary=NSDictionaryOfVariableBindings(cancelButton,acceptButton);


生成的字典为当然,不嫌累的话自己手写也未尝不可。现在字典啊数组啊写法相对简化了很多了,因此也不复杂。关于Objective-C的新语法,可以参考我之前的一篇WWDC 2012笔记:vcat.com/2012/06/modern-objective-c/" target="_blank">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. 1[UIViewanimateWithDuration:0.5animations:^{
  2. 2[viewlayoutIfNeeded];
  3. 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中的具体体现如下图:

Alt text

但是我们看到图中的宽度和高度都是Any,Any是什么意思呢?如果weight设为Anyheight设置为Regular,那么在该状态下的界面元素在只要heightRegular,无论weightRegular还是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 )coordinator
              {
                  [super willTransitionToTraitCollection:newCollection 
                               withTransitionCoordinator:coordinator];
                  [coordinator animateAlongsideTransition:^(id  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 BuilderSize Class有了很强大的支持,xib中可以开启Size Classes如下图:

Alt text

在不同的Size Classes描述下,界面元素可以选择安装还是不安装,具体操作如图:

Alt text

Size Classes与Image Asset

Xcode6中Image Asset也支持了Size Class,也就是说,我们可以对不同的Size Class指定不同的图片了。在Image Asset的编辑面板中选择某张图片,Inspector里现在多了一个WidthHeight的组合,添加我们需要对应的Size Class,然后把合适的图拖上去,这样在运行时SDK就将从中挑选对应的Size的图进行替换了。支持Size ClassImage Asset编辑效果如下:

Alt text

 

 


 

 

 

点击复制链接 与好友分享!回本站首页
相关TAG标签 模式
上一篇:iOS Quartz2D 渐变图形 CGGradient CGShading
下一篇:iOS-支持ipv6-only后,开发者应该做些什么??
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站