I am using this code now to spin bottle on button tap:
@IBAction func spinButton(sender: AnyObject) {
let rotateView = CABasicAnimation()
let randonAngle = arc4random_uniform(360) + 720
rotateView.fromValue = 0
rotateView.toValue = Float(randonAngle) * Float(M_PI) / 180.0
rotateView.duration = 3
rotateView.delegate = self
rotateView.repeatCount = 0
rotateView.removedOnCompletion = false
rotateView.fillMode = kCAFillModeForwards
rotateView.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
bottleImageView.layer.addAnimation(rotateView, forKey: "transform.rotation.z")
}
But how can I rotate the button using gesture? So the harder/faster I move my finger, the faster the bottle will spin
The simple answer to this is... use a UIScrollView
.
From my question here... Loop UIScrollView but continue decelerating
Translating it to Swift is trivial but here goes...
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//make the content size really big so that the targetOffset of the deceleration will never be met.
scrollView.contentSize = CGSize(width: CGRectGetWidth(scrollView.frame) * 100.0, height: CGRectGetHeight(scrollView.frame))
//set the contentOffset of the scroll view to a point in the center of the contentSize.
scrollView.setContentOffset(CGPoint(CGRectGetWidth(scrollView.frame) * 50, 0), animated: false)
}
func rotateImageView() {
//Calculate the percentage of one "frame" that is the current offset.
// each percentage of a "frame" equates to a percentage of 2 PI Rads to rotate
let minOffset = CGRectGetWidth(scrollView.frame) * 50.0
let maxOffset = CGRectGetWidth(scrollView.frame) * 51.0
let offsetDiff = maxOffset - minOffset
let currentOffset = scrollView.contentOffset.x - minOffset
let percentage = currentOffset / offsetDiff
arrowView.transform = CGAffineTransformMakeRotation(M_PI * 2 * percentage)
}
func scrollViewDidScroll(scrollView: UIScrollView) {
//the scrollView moved so update the rotation of the image
rotateImageView()
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
//the scrollview stopped moving.
//set the content offset back to be in the middle
//but make sure to keep the percentage (used above) the same
//this ensures the arrow is pointing in the same direction as it ended decelerating
let diffOffset = scrollView.contentOffset.x
while diffOffset >= CGRectGetWidth(scrollView.frame) {
diffOffset = diffOffset - CGRectGetWidth(scrollView.frame)
}
scrollView.setContentOffset(CGPoint(x: CGRectGetWidth(scrollView.frame) * 50 + diffOffset, y: 0), animated:false)
}
In this example my spinning view is the arrowView
. The scrollView
and arrowView
should both be subviews of the view controller's view. The scrollView
should not have anything in it.
N.B. This is done in the browser so there may be some syntax problems. You may also have to cast some of the numbers to CGFloat
etc...
Also, being able to translate from Objective-C is essential for any iOS dev. Millions of apps are written using Objective-C. The syntax may be slightly different but all of the APIs are the same.
Learning how to do this is something that every iOS dev should be doing.
I have managed to create a sample app that has a view in the center which you can spin with UIRotationGestureRecognizer
and spin speed will be affected based on rotation speed. I've used UIDynamics
for this:
class ViewController: UIViewController {
@IBOutlet weak var sampleView: UIView!
var animator: UIDynamicAnimator?
override func viewDidLoad() {
super.viewDidLoad()
setupRotationGesture()
}
override func viewDidAppear(animated: Bool) {
animator = UIDynamicAnimator(referenceView: self.view)
let sampleViewBehavior = UIDynamicItemBehavior(items: [self.sampleView])
sampleViewBehavior.allowsRotation = true // view can rotate
animator?.addBehavior(sampleViewBehavior)
let anchoredSuperViewBehavior = UIDynamicItemBehavior(items: [self.view])
anchoredSuperViewBehavior.anchored = true
animator?.addBehavior(anchoredSuperViewBehavior)
// Attachment between the sample view and super view at center anchor point.
let attachment = UIAttachmentBehavior.pinAttachmentWithItem(self.sampleView, attachedToItem: self.view, attachmentAnchor: CGPointMake(self.view.center.x + 1, self.view.center.y + 1))
animator?.addBehavior(attachment)
}
// MARK: - Rotation Gesture -
func setupRotationGesture(){
let rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotationGesture(_:)))
self.sampleView.addGestureRecognizer(rotationGesture)
}
func handleRotationGesture(gesture: UIRotationGestureRecognizer){
if gesture.state == .Ended {
let push = UIPushBehavior(items: [self.sampleView], mode: .Instantaneous)
push.magnitude = abs(50.5 * gesture.velocity)
let transform = self.sampleView.transform
push.angle = atan2(transform.b, transform.a);
animator?.addBehavior(push)
}
}
}
When you run you will be able to spin the view based on speed of rotation gesture.
Use UIPanGestureRecognizer
. Create a panGestureRecognizer and add it to your bottle's superview and implement it's delegate. It has variables such as velocityInView
, translationInView
. When user finishes panning, Use them to calculate the angle, speed and duration of your spin.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With