I'm having a container view and added a UIPanGestureRecognizer
on it. It works like this image:
With the UIPanGestureRecognizer
it's possible to swipe to the right, and it works great
@objc func respondToSwipeRight(recognizer: UIPanGestureRecognizer) {
container.setAnchorPoint(anchorPoint: .init(x: 1, y: 1))
let touchLocation = recognizer.location(in: container.superview)
let center = container.center
switch recognizer.state{
case .began :
self.deltaAngle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) - atan2(container.transform.b, container.transform.a)
case .changed:
backgroundView.backgroundColor = UIColor.systemGreen
let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x)
let angleDiff = self.deltaAngle - angle
if angleDiff <= 0, angleDiff > -5, angleDiff > -0.50 {
container.transform = CGAffineTransform(rotationAngle: -angleDiff)
}
case .ended:
UIView.animate(withDuration: 0.6, animations: { [weak self] in
guard let this = self else { return }
this.container.transform = CGAffineTransform(rotationAngle: 0)
}, completion: { [weak self] _ in
guard let this = self else { return }
this.container.setAnchorPoint(anchorPoint: .init(x: 0.5, y: 0.5))
})
default: break
}
}
Now, I want to have the same things from right to left, I added a new UIPanGestureRecognizer
to that view, but appearance I only can have one UIPanGestureRecognizer
per view and it uses the latest one.
Could anyone help me to have the same mechanism for right to left? For right to left, the container anchor point should be like that:
container.setAnchorPoint(anchorPoint: .init(x: 0, y: 1))
Your help will be appreciated
CodePudding user response:
Here's an example of using a single UIPanGestureRecognizer
to rotate the box around either the bottom-left or bottom-right corner as the user moves their finger right and left. Be sure to start your pan gesture on the box.
Start with a new iOS app project. Use the following for the ViewController
class. No other changes to the project are needed. Run on your favorite iOS device or simulator.
enum PanDirection {
case unknown
case left
case right
}
class ViewController: UIViewController {
var box: UIView!
var direction: PanDirection = .unknown
override func viewDidLoad() {
super.viewDidLoad()
let container = UIView(frame: .zero)
container.backgroundColor = .systemBlue
container.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(container)
// Just some example constraints to put the box on the screen
NSLayoutConstraint.activate([
container.heightAnchor.constraint(equalToConstant: 250),
container.widthAnchor.constraint(equalTo: container.heightAnchor),
container.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -30),
container.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
])
// The box that will be rotated
// Sized to match the blue container
box = UIView(frame: container.bounds)
box.backgroundColor = .systemGreen
box.autoresizingMask = [.flexibleWidth, .flexibleHeight]
container.addSubview(box)
// Setup the pan gesture and add to the blue container
let pan = UIPanGestureRecognizer(target: self, action: #selector(panHandler))
pan.minimumNumberOfTouches = 1
pan.maximumNumberOfTouches = 1
container.addGestureRecognizer(pan)
}
@objc func panHandler(_ gesture: UIPanGestureRecognizer) {
if gesture.state == .began || gesture.state == .changed {
// Relative offset from the start of the gesture
let offset = gesture.translation(in: gesture.view)
// Determine which direction we are panning
if offset.x == 0 {
direction = .unknown
} else {
direction = offset.x > 0 ? .right : .left
}
if direction == .right {
// How far right we have panned
let right = offset.x
// Only rotate up to 75 degrees - just an example
let angleDeg = min(right / box.bounds.size.width * 90, 75)
// Calculate the transform. We need to translate the box to the bottom-right corner,
// then rotate, then translate back to the center.
let shift = CGAffineTransform(translationX: box.bounds.size.width / 2, y: box.bounds.size.height / 2)
box.transform = shift.rotated(by: angleDeg / 180 * .pi).translatedBy(x: -box.bounds.size.width / 2, y: -box.bounds.size.height / 2)
} else if direction == .left {
// How far to the left we have panned
let left = offset.x
// Only rotate up to 75 degrees - just an example
let angleDeg = max(left / box.bounds.size.width * 90, -75)
// Calculate the transform. We need to translate the box to the bottom-left corner,
// then rotate, then translate back to the center.
let shift = CGAffineTransform(translationX: -box.bounds.size.width / 2, y: box.bounds.size.height / 2)
box.transform = shift.rotated(by: angleDeg / 180 * .pi).translatedBy(x: box.bounds.size.width / 2, y: -box.bounds.size.height / 2)
}
} else {
// Reset for next pan gesture
direction = .unknown
}
}
}
Start a pan in the box - move right and left and the green box rotates back and forth around the appropriate corner as the finger moves.