前言:上章UIKit Dynamics 置身真实世界介绍了基本用法,下面咱们继续深刻学习——手势跟Dynamics结合的用法 #####1、触摸处理 一、在ViewController.swift添加如下属性,并在Main.storyboard
结合这些属性,在Main.storyboard
添加一个imageView
,以及扮演redSquare
,blueSquare
的俩个viewswift
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var redSquare: UIView!
private var originalBounds = CGRect.zero
private var orignalCenter = CGPoint.zero
private var animator: UIDynamicAnimator!
private var attachmentBehavior: UIAttachmentBehavior!
private var pushBehavior: UIPushBehavior!
private var itemBehavior: UIDynamicItemBehavior!
复制代码
blueSquare
将简单地表示您的触摸开始的位置,即您的手指首先与屏幕接触。redSquare
会在您的手指移动时跟踪您的手指。 另外,在view添加一个手势识别器(Pan Gesture Recognizer),打开ViewController.swift并将此新方法添加到该文件中:bash
@IBAction func handleAttachmentGesture(_ sender: UIPanGestureRcodeecognizer) {
let location = sender.location(in: view)
let boxLocation = sender.location(in: imageView)
switch sender.state {
case .began:
print("Your touch start position is \(location)")
print("Start location in image is \(boxLocation)")
case .ended:
print("Your touch end position is \(location)")
print("End location in image is \(boxLocation)")
default:
break
}
}
复制代码
在屏幕上滑动或者拖动下,会打印以下网络
Your touch start position is (73.0, 363.5) Start location in image is (40.0, 226.5) Your touch end position is (72.5, 363.0) End location in image is (39.5, 226.0)dom
#####2、UIDynamicAnimator和UIAttachmentBehavior 设置完简单的UI,如今加上Dynamics,使其动态化 首先,咱们得让imageView跟随咱们的拖动而移动,用到Dynamics
中的一个类--UIAttachmentBehavior
async
打开ViewController.swift并将如下代码放在viewDidLoad()
下面ide
animator = UIDynamicAnimator(referenceView: view)
originalBounds = imageView.bounds
orignalCenter = imageView.center
复制代码
上面的代码设置了一个UIDynamicAnimator
——基于物理动画的UIKit引擎,将视图控制器的视图做为参考视图来定义animator
的坐标系。 咱们能够添加行为到animator
,它容许你作不少事情例如:附着view,推进view,使他们受重力的影响,等等。学习
请在handleAttachmentGesture(sender:)
中的case .began:
两个print
语句下方添加如下代码动画
//1
animator.removeAllBehaviors()
//2
let centerOffset = UIOffset(horizontal: boxLocation.x - imageView.bounds.midX, vertical: boxLocation.y - imageView.bounds.midY)
attachmentBehavior = UIAttachmentBehavior(item: imageView, offsetFromCenter: centerOffset, attachedToAnchor: location)
//3
redSquare.center = attachmentBehavior.anchorPoint
blueSquare.center = location
//4
animator.addBehavior(attachmentBehavior)
复制代码
咱们先来看看上面代码👆:ui
一、首先删除可能存在的任何现有的动画行为。 二、接下来,您建立一个
UIAttachmentBehavior
将imageView
的点附加到用户点击锚点(刚好相同点)的位置。稍后,您将更改锚点,这将致使imageView
移动。 将锚点链接到视图就像安装一个不可见的杆,将锚点链接到视图上的固定附件位置。 三、更新红色方块以指示锚点,蓝色方块表示imageView
中附加的点。当手势开始时,这些将是相同的点。 四、将此行为添加到animator
,使其生效。spa
接下来你须要告诉锚点自己跟随你的手指.将下列代码替换default
的break
语句
attachmentBehavior.anchorPoint = sender.location(in: view)
redSquare.center = attachmentBehavior.anchorPoint
复制代码
拖拽完以后,最好imageView
能够回到初始位置,因此咱们写一个方法func resetPosintion()
func resetPosintion() {
animator.removeAllBehaviors()
UIView.animate(withDuration: 0.45) {
self.imageView.bounds = self.originalBounds
self.imageView.center = self.orignalCenter
self.imageView.transform = CGAffineTransform.identity
}
}
复制代码
接着把 resetPosintion()
放入handleAttachmentGesture
的case .ended:
print语句下面 效果以下:
imageView
立刻回到原始位置,显然咱们更但愿手拖动后,存在惯性,还能够移动一段距离,为了解决这个问题,继续下面的学习 #####3、UIPushBehavior 在中止拖动时分离视图,并赋予动量,使其在运动时释放时能够继续其轨迹 首先,添加两个常量到顶部:
let ThrowingThreshold: CGFloat = 1000
let ThrowingVelocityPadding: CGFloat = 35
复制代码
ThrowingThreshhold
指示视图必须移动多快以使视图继续移动(而不是当即返回到原始位置)。ThrowingVelocityPadding
是一个魔法常数,影响运动多快或者多慢(这是经过反复试验选择的)。
替换上面的case.end :
的resetPosintion()
// 1
let velocity = sender.velocity(in: view)
let magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y))
if magnitude > ThrowingThreshold {
// 2
let pushBehavior = UIPushBehavior (items: [imageView], mode: .instantaneous)
pushBehavior.pushDirection = CGVector(dx: velocity.x / 10, dy: velocity.y / 10)
pushBehavior.magnitude = magnitude / ThrowingVelocityPadding
self.pushBehavior = pushBehavior
animator.addBehavior(pushBehavior)
// 3
let angle = Int(arc4random_uniform(20)) - 10
itemBehavior = UIDynamicItemBehavior(items: [imageView])
itemBehavior.friction = 0.2
itemBehavior.allowsRotation = true
itemBehavior.addAngularVelocity(CGFloat(angle), for: imageView)
animator.addBehavior(itemBehavior)
// 4
let timeOffset = Int64(0.4 * Double(NSEC_PER_SEC))
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(timeOffset) / Double(NSEC_PER_SEC)) {
self.resetPosition()
}
} else {
resetPosition()
}
复制代码
咱们先来看看这一节:
一、询问手势的拖动速度。 使用速度和你的老朋友毕达哥拉斯定理,你能够计算速度的大小 - 这是由x方向速度和y方向速度造成的三角形的斜边。
二、假设手势幅度超过为动做设置的最小阈值,则设置推送行为。 推进行为对指定的项目施加力。 在这种状况下,它是对图像的瞬时力量。 指望的方向由转换为给出方向部分的向量的x和y速度组成。 一旦设置了推进行为,就将其添加到动画序列中。
四、在指定的时间间隔以后,动画会经过将图像发送回目的地重置,所以它会拉出并返回屏幕 - 就像一个球从墙上弹起! 效果以下: