玩转iOS 9的UIDynamics(转)
转自 http://www.cocoachina.com/ios/20150716/12613.html
本文由CocoaChina翻译小组成员AGSpider(微博)翻译自fancypixel的博客,
原文:Playing With UIDynamics in iOS 9
UIDynamics在iOS7 SDK中是一个受欢迎的新加特性, 它基本上是一个支持UIView的物理引擎,可以让我们自定义UI 控件的物理特性。这个API浅显易懂,你可以轻松地创建很棒的动画或者过渡效果。之前我在 这篇文章 中已经涵盖了其基本要点, 而这一次,我们将看看iOS 9里的UIDynamics有什么新玩意。
碰撞边界(Collision Bounds)
UIDynamics 的第一个版本带有碰撞系统(在 UICollisionBehavior 中)只支持矩形。这可以理解,因为UIViews都是矩形架构,但是圆形的却不常见,更不用说优化一个自定义的贝塞尔曲线。在iOS 9中,UIDynamicItem协议里加了一个新属性:UIDynamicItemCollisionBoundsType,支持以下枚举类型:
Rectangle
Ellipse
Path
这个属性是只读的,如果我们想修改它的话,需要提供我们的子类:
1
2
3
4
5
|
class Ellipse: UIView { override var collisionBoundsType: UIDynamicItemCollisionBoundsType { return .Ellipse } } |
这是默认碰撞边界的UIView。
而这是同一个带.Ellipse属性的UIView。
这涵盖了圆形的视图,如果我们突发奇想,画一个更复杂,有连续的刚体,我们就可以使用.path枚举类型啦,并且也要重写该属性:
1
|
var collisionBoundingPath: UIBezierPath { get } |
这个路线可以是任意你能所想到的,只要它的样子是凸面的(即任意在多边形内两个的点,两点间的线段完全包含在多边形内),并且是逆时针绕的。凸面这个条件也许限制的太死了,于是引入了UIDynamicItemGroup,它可以详细描绘一组不同图形的的组合图形。这样,只要该组合中的每个图形都是凸面,即使得到的多边形是凹面的也OK。
Field Behavior
Field Behavior是在整个场景中运用的一种新behavior。一个最普通的例子就是我们一直默默地使用着的UIGravityBehavior,即场景中的每个物体都会受到一个向下的重力。现在我们可以使用一组新的场力,就像径向(距离场景中心越近,力越大)、噪声(在场景内随机产生的不同的力)等等。
Dynamic Item Behavior(动力元素行为)
UIDynamicItemBehavior 包含了几个有趣的新特性:
var charge: CGFloat
var anchored: Bool
charge 代表能够影响一个元素在电磁场上如何移动的电荷(是的,听起来很疯狂),而anchored本质上是将图形变成了碰撞中的一个静态物体,但没有响应事件(如果有什么东西撞上了它,它会丝毫不动),所以可以完美地用来表示地板或墙壁。
Attachment Behavior(吸附行为)
UIAttachmentBehavior改进后,现在像个具有新方法和属性的侦探,如同frictionTorque和attachmentRange一样。现在吸附行为变得更加灵活,我们可以指定相对滑动的动作、固定吸附、绳索链接和我最喜欢的:针型吸附。想像一下两个钉在一起的物体你就明白了。这些基本涵盖了UIDynamics的新特性,现在,是时候丢下这个更新日志,并开始搭建一些很二的东西了。
让我们玩球吧
我上周花了很多时间在球王(Ball King)上。这一个很棒的消磨时间的东西,这游戏的的理念很简单,但是表现很出色。并且,它采用了获得苹果设计奖的Crossy Roadde 相同的理念:它不会以任何方式影响到玩家,比如游戏内的荣誉。
我非常喜欢它的一点是球的物理模型,以及当球打到篮板上时篮板的反应。看起来用它来测试上面提到的UIDynamics新特性应该会非常不错。让我们来看看如何一步步地打造属于自己的简单的版本吧:BallSwift
篮框
篮球架可以用一个UIView作为篮板,几个UIView作为篮框的左右两边,最前面的view作为篮框本身(不带物理刚体)。使用我们之前定义的类Ellipse,我们就可以创造我们的游戏场景的视觉表现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/* Build the hoop, setup the world appearance */ func buildViews() { board = UIView(frame: CGRect(x: hoopPosition.x, y: hoopPosition.y, width: 100, height: 100)) board.backgroundColor = .whiteColor() board.layer.borderColor = UIColor(red: 0.98, green: 0.98, blue: 0.98, alpha: 1).CGColor board.layer.borderWidth = 2 board.addSubview({ let v = UIView(frame: CGRect(x: 30, y: 43, width: 40, height: 40)) v.backgroundColor = .clearColor() v.layer.borderColor = UIColor(red: 0.4, green: 0.4, blue: 0.4, alpha: 1).CGColor v.layer.borderWidth = 5 return v }()) leftHoop = Ellipse(frame: CGRect(x: hoopPosition.x + 20, y: hoopPosition.y + 80, width: 10, height: 6)) leftHoop.backgroundColor = .clearColor() leftHoop.layer.cornerRadius = 3 rightHoop = Ellipse(frame: CGRect(x: hoopPosition.x + 70, y: hoopPosition.y + 80, width: 10, height: 6)) rightHoop.backgroundColor = .clearColor() rightHoop.layer.cornerRadius = 3 hoop = UIView(frame: CGRect(x: hoopPosition.x + 20, y: hoopPosition.y + 80, width: 60, height: 6)) hoop.backgroundColor = UIColor(red: 177.0/255.0, green: 25.0/255.0, blue: 25.0/255.0, alpha: 1) hoop.layer.cornerRadius = 3 [board, leftHoop, rightHoop, floor, ball, hoop].map({self.view.addSubview($0)}) } |
这里其实没有什么新东西, 篮框以编程形式被创建在常量CGPoint hoopPosition上。但是视图的顺序很重要,因为我们想让篮框要高于篮球(的抛投点)。
螺母和螺栓(Nuts and bolts)
篮框的最重要的部分是左右臂,它们需要一个物理圆形身体(使得与球的碰撞显得自然),需要用螺栓固定在板和前框。这两个将成为基本的UIDynamicItems,并不会直接碰撞参与碰撞。新推出的针型吸附就是为此而生的,它可以把一切都完美地结合在一起,因为我们可以在这个比较粗糙的图画上看到:
在给定的确定空间点内,pin一次仅可连接几个视图:
1
2
3
4
5
6
7
8
9
10
11
|
let bolts = [ CGPoint(x: hoopPosition.x + 25, y: hoopPosition.y + 85), // leftHoop -> Board CGPoint(x: hoopPosition.x + 75, y: hoopPosition.y + 85), // rightHoop -> Board CGPoint(x: hoopPosition.x + 25, y: hoopPosition.y + 85), // hoop -> Board (L) CGPoint(x: hoopPosition.x + 75, y: hoopPosition.y + 85)] // hoop -> Board (R) // Build the board zip([leftHoop, rightHoop, hoop, hoop], offsets).map({ (item, offset) in animator?.addBehavior(UIAttachmentBehavior.pinAttachmentWithItem(item, attachedToItem: board, attachmentAnchor: bolts)) }) |
如果你不准备继续看看swfit版里的奇妙的功能,那你很可能不熟悉zip和map。这一开始看起来似乎有些刻意而为,但其实很简单:每个视图都用一个偏移点钉住吸附,然后我们得到一系列的元组,稍后将会在映射函数中使用。顾名思义,它创建了所给定的物体的数组中的每个元素间的映射。这使得篮框的左右边都用螺栓固定在板和前框,如下:
左臂用螺栓固定在篮板的左侧
右臂用螺栓固定在篮板右侧
篮框用螺栓固定在篮板的左侧
下一个步骤要求我们将篮板悬挂上,别将它固定死,这样球一个碰撞就可以使得它转动,就像在Ball King这个游戏中一样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// Set the density of the hoop, and fix its angle // Hang the hoop animator?.addBehavior({ let attachment = UIAttachmentBehavior(item: board, attachedToAnchor: CGPoint(x: hoopPosition.x, y: hoopPosition.y)) attachment.length = 2 attachment.damping = 5 return attachment }()) animator?.addBehavior({ let behavior = UIDynamicItemBehavior(items: [leftHoop, rightHoop]) behavior.density = 10 behavior.allowsRotation = false return behavior }()) // Block the board rotation animator?.addBehavior({ let behavior = UIDynamicItemBehavior(items: [board]) behavior.allowsRotation = false return behavior }()) |
篮框已经做好了,下面该到篮球了,用一个圆形的自定义UIImageView子类视图,如同Ellipse类:
然后,我们可以将球作为一个普通的UIImageView实例化:
1
2
3
4
5
|
let ball: Ball = { let ball = Ball(frame: CGRect(x: 0, y: 0, width: 28, height: 28)) ball.image = UIImage(named: "ball" ) return ball }() |
最后我们设置他的 物理属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// Set the elasticity and density of the ball animator?.addBehavior({ let behavior = UIDynamicItemBehavior(items: [ball]) behavior.elasticity = 1 behavior.density = 3 behavior.action = { if !CGRectIntersectsRect(self.ball.frame, self.view.frame) { self.setupBehaviors() self.ball.center = CGPoint(x: 40, y: self.view.frame.size.height - 100) } } return behavior }()) |
这段代码里我设置了弹性大小(碰撞后反弹的幅度)、密度(就把它看作重量吧),还有当球超出弹跳范围时立即结束游戏的事件,即为重置游戏状态(在主视图中)。
Collisions and gravity(碰撞和重力)
我提到了UIDynamicItemBehavior的新属性anchored,即禁用了对象的动态behavior,同时将其保留在在碰撞循环里。听起来用它来搭建一个坚固的地板会很不错:
1
2
3
4
5
6
|
// Anchor the floor animator?.addBehavior({ let behavior = UIDynamicItemBehavior(items: [floor]) behavior.anchored = true return behavior }()) |
如果你忘了设置这个属性,你就会抓耳挠腮。反正我是这样的。
好吧,一切都设置好啦,现在只需要一些重力和一组碰撞事件了:
1
2
|
animator?.addBehavior(UICollisionBehavior(items: [leftHoop, rightHoop, floor, ball])) animator?.addBehavior(UIGravityBehavior(items: [ball])) |
重力是应用在默认每秒一点作为的向下的力的场景behavior。碰撞behavior 作为相互碰撞的view的参数。游戏已经搭建好啦,现在我们可以在球上施加一个瞬发力,并用我们的手指划过屏幕:
1
2
3
4
|
let push = UIPushBehavior(items: [ball], mode: .Instantaneous) push.angle = -1.35 push.magnitude = 1.56 animator?.addBehavior(push) |
这下你该明白了吧,虽然场景边缘真的画的很low,但是搭建它真的很有趣(是的,云朵和灌木丛都是一样的勾画,就像 超级马里奥 里中的)。
老规矩,你可以在我们的 GitHub页面 找到源代码。
下次见,
安德烈 - @theandreamazz
玩转iOS 9的UIDynamics(转)的更多相关文章
- 玩转iOS开发:iOS中的GCD开发(三)
上一章, 我们了解到了GCD里的一些队列和任务的知识, 也实践了一下, 同时我们也对主队列的一些小情况了解了一下, 比如上一章讲到的卡线程的问题, 如果没有看的朋友可以去看看玩转iOS开发:iOS中的 ...
- 玩转iOS开发 - 多线程开发
前言 本文主要介绍iOS多线程开发中使用的主要技术:NSOperation, GCD. NSThread, pthread. 内容依照开发中的优先推荐使用的顺序进行介绍,涉及多线程底层知识比較多的NS ...
- 玩转iOS开发 - 简易的实现2种抽屉效果
BeautyDrawer BeautyDrawer 是一款简单易用的抽屉效果实现框架,集成的属性能够对view 滑动缩放进行控制. Main features 三个视图,主视图能够左右滑动.实现抽屉效 ...
- 玩转iOS开发 - 数据缓存
Why Cache 有时候.对同一个URL请求多次,返回的数据可能都是一样的,比方server上的某张图片.不管下载多少次,返回的数据都是一样的. 上面的情况会造成下面问题 (1)用户流量的浪费 (2 ...
- 玩转iOS开发 - JSON 和 Xml 数据解析
前言 Json 和xml是网络开发中经常使用的数据格式,JSON轻量级.xml相对较复杂.所以如今用JSON的比例很大.基本上从server获取的返回数据都是JSON格式的,作为iOS开发人员,解析J ...
- 玩转 iOS 10 推送 —— UserNotifications Framework(合集)
iOS 10 came 在今年 6月14号 苹果开发者大会 WWDC 2016 之后,笔者赶紧就去 apple 的开发者网站下载了最新的 Xcode 8 beta 和 iOS 10 beta,然后在自 ...
- 掌握这些技能玩转iOS
近一年来,苹果iOS/OS X频繁被爆出重大安全漏洞,攻击者可以通过漏洞窃取多达上千个应用的密码.这些漏洞一旦被黑客掌握.利用,后果不堪设想. 好在这些漏洞的发现者还是有节操的,他们都将这些漏洞汇报给 ...
- 玩转iOS开发 - 消息推送
消息推送
- 玩转iOS开发 - 视图控制器生命周期
视图控制器生命周期
随机推荐
- SKYLINE
uvalive4108:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&pag ...
- HDOJ(HDU) 2186 悼念512汶川大地震遇难同胞——一定要记住我爱你
Problem Description 当抢救人员发现她的时候,她已经死了,是被垮塌下来的房子压死的,透过那一堆废墟的的间隙可以看到她死亡的姿势,双膝跪着,整个上身向前匍匐着,双手扶着地支撑着身体,有 ...
- wait和waitpid的使用和区别
昨天看到一则新闻,讲的是一个游戏开发大拿猝死去世的新闻,公司发了讣告,打算接下去给他爸爸妈妈每个月10000的赡养费,很是感慨,本来中国的游戏业和国外就差距大,天妒英才啊.真心想对那些游戏公司的领导说 ...
- Docker网络模式
[编者的话] 本文是<Docker网络及服务发现>一书的一个章节,介绍了搭建Docker单主机网络的基础内容.关于Docker网络的更多内容,包括多主机的网络,请参考该书的其他章节. @C ...
- Java 中 StringBuilder 在高性能用法总结
关于StringBuilder,一般同学只简单记住了,字符串拼接要用StringBuilder,不要用+,也不要用StringBuffer,然后性能就是最好的了,真的吗吗吗吗? 还有些同学,还听过三句 ...
- Palindrome - POJ 3974 (最长回文子串,Manacher模板)
题意:就是求一个串的最长回文子串....输出长度. 直接上代码吧,没什么好分析的了. 代码如下: ================================================= ...
- redis和ehcache
Ehcache在java项目广泛的使用.它是一个开源的.设计于提高在数据从RDBMS中取出来的高花费.高延迟采取的一种缓存方案.正因为Ehcache具有健壮性(基于java开发).被认证(具有apac ...
- 作业.把c语言输出的基础差不多都概括了!
// (1)1英里=1.60931公里,从键盘上输入英里数输出公里数 #include "stdio.h" #define PI 3.1415926 #include " ...
- 隐式intent
使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动, 这里我们首先指定了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的 ...
- 南阳理工ACM-OJ 分数加减法 最大公约数的使用
http://acm.nyist.net/JudgeOnline/problem.php?pid=111 简单模拟: #include <iostream> #include <st ...