UIKit Dynamics 教程:抛掷 Views
来源:互联网 发布:阿里巴巴上传淘宝代销 编辑:程序博客网 时间:2024/05/16 13:39
本文译自:UIKit Dynamics Tutorial: Tossing Views
本文中,我们将学习如何用手势很自然的将 view 抛掷出屏幕。
可能你已经看到该技术在 Tweetbot 中的流行了。
本文非常适合中级开发者,因为对 view 抛掷操作中,使用的技术嵌套了多个效果,例如使用内置的 UIKit 框架对 view 进行旋转 (rotation)、飞离 (fly-away) 动画。
如果你之前还不了解 UIKit dynamics,也不用担心 - 本文会一步一步的引导你进行学习。
事不宜迟,我们开始抛掷 view 吧!
目录:
- 开始
- UIDynamicAnimator 和 UIAttachmentBehavior
- UIPushBehavior
- 何去何从?
开始
提醒:学习中,本节是可选的,主要是针对想要从零开始的读者。有经验的 iOS 开发者可以忽略本节,直接到下一节 (已经为你准备好一个工程了)。
打开 Xcode,选择 File\New\Project…
,选择 iOS\Application\Single View Application
模板,然后点击 Next
。将工程命名为 DynamicToss
,并将 device family 设置为 iPhone。
现在选中左边的工程名称,并确保选中 Xcode 窗口顶部的 General。在 Deployment Info/Device Orientation
中,不要勾选 ‘Landscape Left’ and ‘Landscape Right’,因为这个程序只以 portrait 模式运行。
接着下载一个图片,这个图片来自gameartguppy.com:
将工程解压出来,然后将图片文件添加到工程中。
接着,打开 Main.storyboard
,并添加一个 image view 控件,相关值设置为:(X=33, Y=137, Width=254, Height=172, Image=goldfish_feature.jpg)。现在屏幕上的看起来应该是这样的:
接着,拖两个 UIView 到 view controller 中,这两个 UIView 用来对手势进行跟踪。按照下面的值进行设置:
- View 1: (X=156, Y=219, Width=8, Height=8, Background=red)
- View 2: (X=80, Y=420, Width=8, Height=8. Background=blue)
至此,view 看起来应该是这样的:
将下面的私有属性添加到 RWTViewController.m
中:
1234567891011
@property (nonatomic, weak) IBOutlet UIView *image;@property (nonatomic, weak) IBOutlet UIView *redSquare;@property (nonatomic, weak) IBOutlet UIView *blueSquare;@property (nonatomic, assign) CGRect originalBounds;@property (nonatomic, assign) CGPoint originalCenter;@property (nonatomic) UIDynamicAnimator *animator;@property (nonatomic) UIAttachmentBehavior *attachmentBehavior;@property (nonatomic) UIPushBehavior *pushBehavior;@property (nonatomic) UIDynamicItemBehavior *itemBehavior;
选中 Main.storyboard
文件,并右键单击 View Controller
。拖拽住出现的 blueSquare
outlet,将其与蓝色正方形 view 连接上:这个动作会将属性连接至 view 对象。
同样也把红色正方形连接好,最后是名字位 image
的属性。现在 3 个 view 属性应该已经连接好了,看起来如下图所示:
红色和蓝色的正方形代表 UIDynamics 物理引擎对图像进行动画效果的点。
蓝色正方形简单的代表触摸的开始,例如,你的手指与屏幕第一次交互时的位置。红色的正方形用来跟踪手指的移动。
你需要对 UIDynamics 框架进行配置,以使得当移动点时,图片也跟着串联的方式做物理动画。
现在还有一件事件需要做 - 为 view 配置一个手势识别。打开 RWTViewController.m
,将下面的方法添加到文件中:
12345678910111213141516171819202122
- (IBAction) handleAttachmentGesture:(UIPanGestureRecognizer*)gesture{CGPoint location = [gesture locationInView:self.view];CGPoint boxLocation = [gesture locationInView:self.image];switch (gesture.state) {case UIGestureRecognizerStateBegan:{NSLog(@"you touch started position %@",NSStringFromCGPoint(location));NSLog(@"location in image started is %@",NSStringFromCGPoint(boxLocation));break;}case UIGestureRecognizerStateEnded: {NSLog(@"you touch ended position %@",NSStringFromCGPoint(location));NSLog(@"location in image ended is %@",NSStringFromCGPoint(boxLocation));break;}default:break;}}
我们将要添加一个手势识别,来检测拖拽,也称为平移 (panning),当事件发生时,会调用上面这个方法。目前,这个方法简单的显示出手指在两个不同坐标系空间 (view 和 image view) 的位置。
为了添加手势识别,打开 Main.storyboard
,并拖一个 Pan Gesture Recognizer
到 view 中。然后从 Pan Gesture Recognizer
control-drag 到我们的 View Controller
,并将其连接到 handleAttachmentGesture:
方法上。
现在编译并运行程序。在屏幕上轻扫或者拖动,可以在控制台看到类似如下信息:
1234
2014-07-13 14:01:49.666 DynamicToss[3999:60b] you touch started position {127, 365}2014-07-13 14:01:49.667 DynamicToss[3999:60b] location in image started is {94, 228}2014-07-13 14:01:50.097 DynamicToss[3999:60b] you touch ended position {113, 464}2014-07-13 14:01:50.097 DynamicToss[3999:60b] location in image ended is {80, 327}
非常棒!现在已经完成了基本的 UI 配置 - 接下来是时候开始 dynamic了!
UIDynamicAnimator 和 UIAttachmentBehavior
提醒:如果你忽略了上一章节的内容,请先从这里下载为你准备好的工程。
首先我们要做的事情就是让 image view 跟随我们的拖拽一起移动。这将通过 UIKit Dynamics中的 UIAttachmentBehavior
来实现。
打开 RWTViewController.m
,并将下面的代码添加到 viewDidLoad
中,位于 [super viewDidLoad]
下方:
123
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];self.originalBounds = self.image.bounds;self.originalCenter = self.image.center;
上面的代码将配置一个 UIDynamicAnimator
,这是 UIKit 中的一个引擎,用于支持最基本的物理动画效果。参照 self.view
定义了 animator 的坐标系。
通过给 animator 添加行为 (behaviors),可以让你做一些事情,例如具有重力效果的进行 attaching view、pushing view等。
下面我们开始给 animator 添加第一个行为:UIAttachmentBehavior
- 使得 image view 跟着手指的手势进行移动。
为了完成这样的效果,将下面的代码添加到 handleAttachmentGesture:
中,位于 case UIGestureRecognizerStateBegan
的两个 NSLog 语句下方:
123456789101112131415
// 1[self.animator removeAllBehaviors];// 2UIOffset centerOffset = UIOffsetMake(boxLocation.x - CGRectGetMidX(self.image.bounds),boxLocation.y - CGRectGetMidY(self.image.bounds));self.attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.imageoffsetFromCenter:centerOffsetattachedToAnchor:location];// 3self.redSquare.center = self.attachmentBehavior.anchorPoint;self.blueSquare.center = location;// 4[self.animator addBehavior:self.attachmentBehavior];
我们来细看一下上述代码的作用:
- 首先移除 animator 中所有已有的行为。
- 创建一个
UIAttachmentBehavior
,将用户 tap image view 上的点连接到一个锚点 (anchor point) 上 (实际上这恰好是完全相同的点)。随后,对锚点的改变,会引发 image view 的移动。
将锚点连接到一个 view 上,就像安装了一个无形的拉杆:将锚点连接到 view 中固定的位置上。
- 更新红色正方形,表示出锚点,而蓝色正方形则表示连接到 image view 内部的点 (现在他们都是一样的)。
- 将这个行为添加到 animator 中,使其具有效果。
接下来需要告诉锚点跟住你的手指。为此,将下面的代码添加到 handleAttachmentGesture:
,位于 fefault
(与手势变化一起改变):
12
[self.attachmentBehavior setAnchorPoint:[gesture locationInView:self.view]];self.redSquare.center = self.attachmentBehavior.anchorPoint;
上面的代码将锚点和红色正方形设置位手指当前的位置。当手指移动时,手势识别会调用这个方法,以更新相应的锚点信息。另外,animator 也会自动的按照这个锚点对 view 进行更新。
编译并运行程序,现在可以拖拽 view 了:
当完成拖拽,要是能降 view 还原到之前的位置就更好了。为此,将下面的方法添加到文件中:
12345678910
- (void)resetDemo{[self.animator removeAllBehaviors];[UIView animateWithDuration:0.45 animations:^{self.image.bounds = self.originalBounds;self.image.center = self.originalCenter;self.image.transform = CGAffineTransformIdentity;}];}
然后在方法 handleAttachmentGesture:
中调用这个方法,具体位于 UIGestureRecognizerStateEnded
:
1
[self resetDemo];
编译并运行程序,现在完成对图片的拖拽之后,该图片应该能够回到最开始的位置。
UIPushBehavior
接下来,我们要完成这样的效果:当停止拖拽时,将 view 从屏幕中移除。那么当手势释放时,需要给这个 view 赋予动量,让它能继续沿着轨迹前行。为此,需要使用 UIPushBehavior
。
首先,定义两个常量,将其添加到文件头部:
12
static const CGFloat ThrowingThreshold = 1000;static const CGFloat ThrowingVelocityPadding = 35;
为了让 view 持续移动,其中 ThrowingThreshold
表示 view 必须移动 (相对于立即返回到原点) 多快才行。ThrowingVelocityPadding
是一个神奇的常量,它将对抛掷 view 的快慢产生影响 (这需要反复试验得出结果)。
最后,在 handleAttachmentGesture:
中,用下面的代码替换 UIGestureRecognizerStateEnded
case:
12345678910111213141516171819202122232425262728293031323334353637
case UIGestureRecognizerStateEnded: {[self.animator removeBehavior:self.attachmentBehavior];//1CGPoint velocity = [gesture velocityInView:self.view];CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));if (magnitude > ThrowingThreshold) {//2UIPushBehavior *pushBehavior = [[UIPushBehavior alloc]initWithItems:@[self.image]mode:UIPushBehaviorModeInstantaneous];pushBehavior.pushDirection = CGVectorMake((velocity.x / 10) , (velocity.y / 10));pushBehavior.magnitude = magnitude / ThrowingVelocityPadding;self.pushBehavior = pushBehavior;[self.animator addBehavior:self.pushBehavior];//3NSInteger angle = arc4random_uniform(20) - 10;self.itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.image]];self.itemBehavior.friction = 0.2;self.itemBehavior.allowsRotation = YES;[self.itemBehavior addAngularVelocity:angle forItem:self.image];[self.animator addBehavior:self.itemBehavior];//4[self performSelector:@selector(resetDemo) withObject:nil afterDelay:0.4];}else {[self resetDemo];}break;}
我们来看看代码都做了些什么:
- 获得手势的拖拽速度。
利用速度和勾股定理 (Pythagorean theorem),计算出速度的幅度 - 也就是由 x 方向上的速度和 y 方向上的速度构成的三角形斜边。
要想理解背后的理论,请看 Trigonometry for Game Programming tutorial。
- 假设手势的幅度超过了最低阀值,那么就配置一个 push behavior。
push behavior 可以是持续性的,或者瞬间的应用到某个对象中。这里,我们需要给 image 一个瞬间的 push 行为。
我们希望 image 的移动方向是由 x 和 y 轴上的速度转换为一个矢量决定的。最后,将 push 行为添加到 animator 上。
- 在这里给 image 添加一些旋转效果,让图片飞离屏幕。这里有复杂的数学知识介绍。
其中的一些效果取决于发起手势操作的手指与边缘的距离。
在此处,设置不同的值,观察它们移动的效果,然后使用最好的那个值即可。
- 指定时间间隔之后,以动画的形式将 imamge 还原到最初状态。
编译并运行程序,现在你应该可以用令人愉快的方式将 view 抛出屏幕!
何去何从?
这里可以下载到本文的最终示例工程。
恭喜你,你现在已经学会如何做一些有趣的 UIKit dynamic 动画了 - 让程序的界面效果非常甜蜜。
如果你想要学习更多关于 UIKit Dynamics 的知识,可以阅读 iOS 7 for Tutorials 中两章 UIKit Dynamics 内容。
- UIKit Dynamics 教程:抛掷 Views
- UIKit Dynamics 教程:抛掷 Views
- UIKit Dynamics
- UIKit Dynamics
- iOS UIKit Dynamics 系列教程之Gravity+Collision
- UIKit动力学(UIKit Dynamics)
- IOS7开发~UIKit Dynamics
- UIKit Dynamics入门
- Introduction to UIKit Dynamics
- UIKit Dynamics Tutorial
- 【iOS开发】UIKit Dynamics
- UIKit Dynamics Tutorial
- IOS7 UIKit Dynamics Tutorial
- UIKit Dynamics入门
- 初窥UIKit Dynamics
- UIKit Dynamics入门
- iOS7 UIKit Dynamics
- UICollectionView和UIKit Dynamics
- 双核处理器的双核是什么意思?
- maven系列--maven常用命令
- 几种常用的java 实现反转的方法(reverse
- linux gcc过程
- MySQL存储引擎MyISAM与InnoDB的主要区别对比
- UIKit Dynamics 教程:抛掷 Views
- 浏览器同源策略以及跨域请求时可能遇到的问题
- arcgis for android 学习 - (7) 在真机上 模拟GPS
- ecplise配置打开文件所在文件夹
- 关于读书
- JS特色快排实现
- IOS开发之实现App消息推送(最新)
- 中缀表达式的计算(含出错处理,括号处理)
- jQuery使用get()方法访问经典的DOM