UIkit Dynamics 投擲效果

圖片來源於網絡

前言:上章UIKit Dynamics 置身真實世界介紹了基本用法,下面咱們繼續深刻學習——手勢跟Dynamics結合的用法 #####1、觸摸處理 一、在ViewController.swift添加如下屬性,並在Main.storyboard結合這些屬性,在Main.storyboard添加一個imageView,以及扮演redSquareblueSquare的倆個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中的一個類--UIAttachmentBehaviorasync

打開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

一、首先刪除可能存在的任何現有的動畫行爲。 二、接下來,您建立一個UIAttachmentBehaviorimageView的點附加到用戶點擊錨點(剛好相同點)的位置。稍後,您將更改錨點,這將致使imageView移動。 將錨點鏈接到視圖就像安裝一個不可見的杆,將錨點鏈接到視圖上的固定附件位置。 三、更新紅色方塊以指示錨點,藍色方塊表示imageView中附加的點。當手勢開始時,這些將是相同的點。 四、將此行爲添加到animator,使其生效。spa

接下來你須要告訴錨點自己跟隨你的手指.將下列代碼替換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立刻回到原始位置,顯然咱們更但願手拖動後,存在慣性,還能夠移動一段距離,爲了解決這個問題,繼續下面的學習 #####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速度組成。 一旦設置了推進行爲,就將其添加到動畫序列中。

四、在指定的時間間隔以後,動畫會經過將圖像發送回目的地重置,所以它會拉出並返回屏幕 - 就像一個球從牆上彈起! 效果以下:

相關文章
相關標籤/搜索