如何像在半球上移动的图层一样使用UIPanGestureRecognizer
与180度一起旋转和变换,我尝试做一些事情,可以在所有方向上进行变换,但方向之间的过渡并不平滑>
简而言之,我想成为like in this video
我只是对这些类进行了编码,它适用于所有方向,但结果并不理想:
//
// MoveCircleToolViewController.swift
//
// Created by Coder ACJHP on 17.06.2020.
// Copyright © 2020 Coder ACJHP. All rights reserved.
//
import UIKit
class MoveCircleToolViewController: UIViewController {
var currentAngleX: CGFloat = 0
var currentOffsetX: CGFloat = 0
var currentAngleY: CGFloat = 0
var currentOffsetY: CGFloat = 0
var cardSize: CGSize = .zero
let transformLayer = CATransformLayer()
var directionsFrames = Array<CGRect>()
override func viewDidLoad() {
super.viewDidLoad()
let panGesture = UIPanGestureRecognizer(target: self,action: #selector(handlePan(_:)))
view.addGestureRecognizer(panGesture)
transformLayer.frame = view.bounds
view.layer.addSublayer(transformLayer)
/// Add simple CALayer (circle shape)
addCircleView()
/** Calculate 4 corners TR,TL,BR,BL and store them in array list
to use them inside pan gesture event */
calculateCorners()
}
private func degreeToRadians(degree: CGFloat) -> CGFloat {
return (degree * CGFloat.pi) / 180
}
private func addCircleView() {
let singleSideSize = self.view.bounds.width * 0.18
cardSize = CGSize(width: singleSideSize,height: singleSideSize)
let imageLayer = CALayer()
let origin = CGPoint(x: (view.bounds.width / 2) - (cardSize.width / 2),y: (view.bounds.height / 2) - (cardSize.height / 2))
imageLayer.frame = CGRect(origin: origin,size: cardSize)
imageLayer.contentsGravity = .resizeAspectFill
imageLayer.borderColor = UIColor.cyan.cgColor
imageLayer.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5).cgColor
imageLayer.borderWidth = 3.0
imageLayer.cornerRadius = cardSize.width / 2
imageLayer.masksToBounds = true
imageLayer.isDoubleSided = true
transformLayer.addSublayer(imageLayer)
}
private func calculateCorners() {
let quarterW = self.view.bounds.width / 2
let quarterH = self.view.bounds.height / 2
let topLeftRect = CGRect(x: 0,y: 0,width: quarterW - cardSize.width / 2,height: quarterH - cardSize.height / 2)
let topRightRect = CGRect(x: topLeftRect.width + cardSize.width,height: quarterH - cardSize.height / 2)
let bottomLeftRect = CGRect(x: 0,y: topLeftRect.height + cardSize.height,height: quarterH - cardSize.height / 2)
let bottomRightRect = CGRect(x: bottomLeftRect.width + cardSize.height,y: topRightRect.height + cardSize.height,height: quarterH - cardSize.height / 2)
directionsFrames.append(topLeftRect)
directionsFrames.append(topRightRect)
directionsFrames.append(bottomLeftRect)
directionsFrames.append(bottomRightRect)
}
@objc
private func handlePan(_ gestureRecognier: UIPanGestureRecognizer) {
let translationPoint = gestureRecognier.translation(in: view)
let location = gestureRecognier.location(in: view)
/// Calculate X and Y offset for animation
let xOffset = gestureRecognier.translation(in: view).x
let yOffset = gestureRecognier.translation(in: view).y
/// Reset offsets
if gestureRecognier.state == .began {
currentOffsetX = 0
currentOffsetY = 0
}
/// Calculate angle for rotation X
let xDifference = xOffset * 0.6 - currentOffsetX
currentOffsetX += xDifference
currentAngleX += xDifference
let angleOffsetX = currentAngleX
/// Calculate angle for rotation Y
let yDifference = yOffset * 0.6 + currentOffsetY
currentOffsetY -= yDifference
currentAngleY -= yDifference
let angleOffsetY = currentAngleY
/// Create transform object
var transform = CATransform3DIdentity
transform.m34 = -1 / self.view.bounds.width
// Top Left
if directionsFrames[0].contains(location) {
transform = CATransform3DRotate(transform,degreeToRadians(degree: 30),1,0)
transform = CATransform3DTranslate(transform,translationPoint.x,translationPoint.y,200)
// Top Right
} else if directionsFrames[1].contains(location) {
transform = CATransform3DRotate(transform,200)
// Bottom Left
} else if directionsFrames[2].contains(location) {
transform = CATransform3DRotate(transform,degreeToRadians(degree: -30),200)
// Bottom Right
} else if directionsFrames[3].contains(location) {
transform = CATransform3DRotate(transform,200)
} else {
if let direction = gestureRecognier.direction {
switch direction {
case .Left,.Right:
transform = CATransform3DRotate(transform,degreeToRadians(degree: angleOffsetX),0)
transform = CATransform3DTranslate(transform,200)
case .Up,.Down:
transform = CATransform3DRotate(transform,degreeToRadians(degree: angleOffsetY),200)
}
}
}
CATransaction.setanimationDuration(0)
transformLayer.transform = transform
}
}
public extension UIPanGestureRecognizer {
enum PanDirection: Int {
case Up,Down,Left,Right
public var isVertical: Bool { return [.Up,.Down].contains(self) }
public var isHorizontal: Bool { return !isVertical }
}
var direction: PanDirection? {
let translation = self.translation(in: view)
let isVertical = abs(translation.y) > abs(translation.x)
switch (isVertical,translation.x,translation.y) {
case (true,_,let y) where y < 0: return .Up
case (true,let y) where y > 0: return .Down
case (false,let x,_) where x > 0: return .Right
case (false,_) where x < 0: return .Left
default: return nil
}
}
}
预先感谢