UIkit Dynamics 投掷效果

前言:上章UIKit Dynamics 置身真实世界介绍了基本用法,下面我们继续深入学习——手势跟Dynamics结合的用法 #####一、触摸处理 1、在ViewController.swift添加以下属性,并在Main.storyboard结合这些属性,在Main.storyboard添加一个imageView,以及扮演redSquareblueSquare的俩个view

    @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并将此新方法添加到该文件中:

    @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)

#####二、UIDynamicAnimator和UIAttachmentBehavior 设置完简单的UI,现在加上Dynamics,使其动态化 首先,我们得让imageView跟随我们的拖动而移动,用到Dynamics中的一个类--UIAttachmentBehavior

打开ViewController.swift并将以下代码放在viewDidLoad()下面

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)
复制代码

我们先来看看上面代码?:

1、首先删除可能存在的任何现有的动画行为。 2、接下来,您创建一个UIAttachmentBehaviorimageView的点附加到用户点击锚点(恰好相同点)的位置。稍后,您将更改锚点,这将导致imageView移动。 将锚点连接到视图就像安装一个不可见的杆,将锚点连接到视图上的固定附件位置。 3、更新红色方块以指示锚点,蓝色方块表示imageView中附加的点。当手势开始时,这些将是相同的点。 4、将此行为添加到animator,使其生效。

接下来你需要告诉锚点本身跟随你的手指.将下列代码替换defaultbreak语句

  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()放入handleAttachmentGesturecase .ended:print语句下面 效果如下:

但是很明显,我们一放开拖动, imageView马上回到原始位置,显然我们更希望手拖动后,存在惯性,还可以移动一段距离,为了解决这个问题,继续下面的学习 #####三、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()
}
复制代码

我们先来看看这一节:

1、询问手势的拖动速度。 使用速度和你的老朋友毕达哥拉斯定理,你可以计算速度的大小 - 这是由x方向速度和y方向速度形成的三角形的斜边。

2、假设手势幅度超过为动作设置的最小阈值,则设置推送行为。 推动行为对指定的项目施加力。 在这种情况下,它是对图像的瞬时力量。 期望的方向由转换为给出方向部分的向量的x和y速度组成。 一旦设置了推动行为,就将其添加到动画序列中。

4、在指定的时间间隔之后,动画会通过将图像发送回目的地重置,因此它会拉出并返回屏幕 - 就像一个球从墙上弹起! 效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值