2017-08-22 33 views
9

我有這是爲了響應捏圖像,旋轉和平移手勢的視圖。我想要捏和圖像的旋轉將相對於放置在屏幕的中間定位點來完成,正是因爲它使用Xcode的iPhone模擬器按選項鍵完成。我怎樣才能把在屏幕中間的錨點如果圖像的中心可能被縮放和平移,以不同的位置?廣場錨點,而這樣做的手勢

這裏是我的縮放和旋轉手勢功能:

@IBAction func pinchGesture(_ gestureRecognizer: UIPinchGestureRecognizer) { 
    // Move the achor point of the view's layer to the touch point 
    // so that scaling the view and the layer becames simpler. 
    self.adjustAnchorPoint(gestureRecognizer: gestureRecognizer) 


    // Scale the view by the current scale factor. 
    if(gestureRecognizer.state == .began) { 
     // Reset the last scale, necessary if there are multiple objects with different scales 
     lastScale = gestureRecognizer.scale 
    } 

    if (gestureRecognizer.state == .began || gestureRecognizer.state == .changed) { 
     let currentScale = gestureRecognizer.view!.layer.value(forKeyPath:"transform.scale")! as! CGFloat 
     // Constants to adjust the max/min values of zoom 
     let kMaxScale:CGFloat = 15.0 
     let kMinScale:CGFloat = 1.0 
     var newScale = 1 - (lastScale - gestureRecognizer.scale) 
     newScale = min(newScale, kMaxScale/currentScale) 
     newScale = max(newScale, kMinScale/currentScale) 
     let transform = (gestureRecognizer.view?.transform)!.scaledBy(x: newScale, y: newScale); 
     gestureRecognizer.view?.transform = transform 
     lastScale = gestureRecognizer.scale // Store the previous scale factor for the next pinch gesture call 
     scale = currentScale // Save current scale for later use 
    } 
} 

@IBAction func rotationGesture(_ gestureRecognizer: UIRotationGestureRecognizer) { 
    // Move the achor point of the view's layer to the center of the 
    // user's two fingers. This creates a more natural looking rotation. 
    self.adjustAnchorPoint(gestureRecognizer: gestureRecognizer) 

    // Apply the rotation to the view's transform. 
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed { 
     gestureRecognizer.view?.transform = (gestureRecognizer.view?.transform.rotated(by: gestureRecognizer.rotation))! 
     // Set the rotation to 0 to avoid compouding the 
     // rotation in the view's transform. 
     angle += gestureRecognizer.rotation // Save rotation angle for later use 
     gestureRecognizer.rotation = 0.0 
    } 
} 

func adjustAnchorPoint(gestureRecognizer : UIGestureRecognizer) { 
    if gestureRecognizer.state == .began { 
     let view = gestureRecognizer.view 
     let locationInView = gestureRecognizer.location(in: view) 
     let locationInSuperview = gestureRecognizer.location(in: view?.superview) 

     // Move the anchor point to the the touch point and change the position of the view 
     view?.layer.anchorPoint = CGPoint(x: (locationInView.x/(view?.bounds.size.width)!), y: (locationInView.y/(view?.bounds.size.height)!)) 
     view?.center = locationInSuperview 
    } 
} 

編輯

我看到人們並不急於進入這個。分享一下我在過去幾天所取得的進展,讓我來幫助。

首先,我寫了一個函數centerAnchorPoint其圖像的錨點正確地放置到屏幕的中心,無論是定位點以前在哪裏。然而,圖像不能縮放或旋轉才能起作用。

func setAnchorPoint(_ anchorPoint: CGPoint, forView view: UIView) { 
    var newPoint = CGPoint(x: view.bounds.size.width * anchorPoint.x, y: view.bounds.size.height * anchorPoint.y) 
    var oldPoint = CGPoint(x: view.bounds.size.width * view.layer.anchorPoint.x, y: view.bounds.size.height * view.layer.anchorPoint.y) 

    newPoint = newPoint.applying(view.transform) 
    oldPoint = oldPoint.applying(view.transform) 

    var position = view.layer.position 
    position.x -= oldPoint.x 
    position.x += newPoint.x 

    position.y -= oldPoint.y 
    position.y += newPoint.y 

    view.layer.position = position 
    view.layer.anchorPoint = anchorPoint 
} 

func centerAnchorPoint(gestureRecognizer : UIGestureRecognizer) { 
    if gestureRecognizer.state == .ended { 

     view?.layer.anchorPoint = CGPoint(x: (photo.bounds.midX/(view?.bounds.size.width)!), y: (photo.bounds.midY/(view?.bounds.size.height)!)) 
    } 
} 

func centerAnchorPoint() { 

    // Position of the current anchor point 
    let currentPosition = photo.layer.anchorPoint 

    self.setAnchorPoint(CGPoint(x: 0.5, y: 0.5), forView: photo) 
    // Center of the image 
    let imageCenter = CGPoint(x: photo.center.x, y: photo.center.y) 
    self.setAnchorPoint(currentPosition, forView: photo) 

    // Center of the screen 
    let screenCenter = CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY) 

    // Distance between the centers 
    let distanceX = screenCenter.x - imageCenter.x 
    let distanceY = screenCenter.y - imageCenter.y 

    // Find new anchor point 
    let newAnchorPoint = CGPoint(x: (imageCenter.x+2*distanceX)/(UIScreen.main.bounds.size.width), y: (imageCenter.y+2*distanceY)/(UIScreen.main.bounds.size.height)) 

    //photo.layer.anchorPoint = newAnchorPoint 
    self.setAnchorPoint(newAnchorPoint, forView: photo) 

    let dotPath = UIBezierPath(ovalIn: CGRect(x: photo.layer.position.x-2.5, y: photo.layer.position.y-2.5, width: 5, height: 5)) 
    layer.path = dotPath.cgPath 
} 

功能setAchorPoint在這裏用來錨點設置到一個新的位置不移動的圖像。

然後,我通過它的結束將這個更新的功能panGesture

if gestureRecognizer.state == .ended { 
     self.centerAnchorPoint() 
    } 

EDIT 2

好了,我會盡量簡單地解釋一下上面的代碼。

什麼我做的是:

  1. 尋找照片的中心和屏幕
  2. 的中心之間的距離套用這個公式找到定位點的新位置:

newAnchorPointX =(imageCenter.x-distanceX)/ screenWidth + distanceX/screenWidth

然後對y位置做同樣的操作。

  • 設置此點作爲新的錨點,而無需使用setAnchorPoint功能
  • 正如我所說的這個工作很大如果圖像不進行縮放移動的照片。如果是,那麼錨點不會停留在中心。

    奇怪的是distanceX或distanceY並不完全依賴於刻度值,所以這樣的事情不是做得比較工作:

    newAnchorPointX =(imageCenter.x-distanceX)/屏幕寬度+ distanceX /(scaleValue *屏幕寬度)

    EDIT 3

    我想出縮放。看來,正確的比例因子是:

    scaleFactor = photo.frame.size.width/photo.layer.bounds.size.width 
    

    我用這個來代替scaleValue,它出色地工作。

    所以完成平移和縮放。剩下的唯一東西就是旋轉,但它似乎是最難的。

    我想的第一件事是到旋轉矩陣適用於X增量和Y方向上,類似這樣的:

    let incrementX = (distanceX)/(screenWidth) 
        let incrementY = (distanceY)/(screenHeight) 
    
        // Applying rotation matrix 
        let incX = incrementX*cos(angle)+incrementY*sin(angle) 
        let incY = -incrementX*sin(angle)+incrementY*cos(angle) 
    
        // Find new anchor point 
        let newAnchorPoint = CGPoint(x: 0.5+incX, y: 0.5+incY) 
    

    然而,這是行不通的。

    +0

    如果圖像放大,然後嘗試乘以distanceX * zoomScale和distanceY相同 –

    +0

    我已更新問題。現在縮放工作正常。唯一剩下的就是旋轉。 – Kaspis245

    回答

    1

    由於問題主要是在編輯中回答,所以我不想重複太多。

    廣義我從張貼在原來問題的代碼更改:

    1. 刪除調用在捏和旋轉手勢功能adjustAnchorPoint功能。
    2. 放置這塊在平移手勢功能碼,以使得錨定點將平移後的照片更新其位置:

      如果gestureRecognizer.state == .ended { self.centerAnchorPoint() }

    3. 已更新centerAnchorPoint函數爲旋轉工作。

    一個完全工作centerAnchorPoint功能(旋轉包括):

    func centerAnchorPoint() { 
         // Scale factor 
         photo.transform = photo.transform.rotated(by: -angle) 
         let curScale = photo.frame.size.width/photo.layer.bounds.size.width 
         photo.transform = photo.transform.rotated(by: angle) 
    
         // Position of the current anchor point 
         let currentPosition = photo.layer.anchorPoint 
    
         self.setAnchorPoint(CGPoint(x: 0.5, y: 0.5), forView: photo) 
         // Center of the image 
         let imageCenter = CGPoint(x: photo.center.x, y: photo.center.y) 
         self.setAnchorPoint(currentPosition, forView: photo) 
    
         // Center of the screen 
         let screenCenter = CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY) 
    
         // Distance between the centers 
         let distanceX = screenCenter.x - imageCenter.x 
         let distanceY = screenCenter.y - imageCenter.y 
    
         // Apply rotational matrix to the distances 
         let distX = distanceX*cos(angle)+distanceY*sin(angle) 
         let distY = -distanceX*sin(angle)+distanceY*cos(angle) 
    
         let incrementX = (distX)/(curScale*UIScreen.main.bounds.size.width) 
         let incrementY = (distY)/(curScale*UIScreen.main.bounds.size.height) 
    
         // Find new anchor point 
         let newAnchorPoint = CGPoint(x: 0.5+incrementX, y: 0.5+incrementY) 
    
         self.setAnchorPoint(newAnchorPoint, forView: photo) 
    } 
    

    這裏要注意的關鍵事情是,旋轉矩陣已被應用到distanceX和distanceY。比例係數也更新爲在整個輪換期間保持不變。