Спиновая бутылка с UIGestureRecognizer

Я использую этот код для вращения бутылки на кнопке:

@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")
    }

Но как я могу повернуть кнопку, используя жест? Так что чем быстрее/быстрее я двигаю пальцем, тем быстрее будет вращаться бутылка

Ответ 1

Простой ответ на этот вопрос: используйте UIScrollView.

Из моего вопроса здесь... Loop UIScrollView, но продолжайте замедление

Перевод его в Swift тривиален, но здесь идет...

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)
}

В этом примере мой поворот - это arrowView. scrollView и arrowView должны быть как субвью в представлении контроллера вида. scrollView не должен иметь ничего в нем.

N.B. Это делается в браузере, поэтому могут возникнуть проблемы с синтаксисом. Возможно, вам также придется отбросить некоторые цифры до CGFloat и т.д.

Кроме того, возможность перевода из Objective-C необходима для любого iOS-разработчика. Миллионы приложений написаны с помощью Objective-C. Синтаксис может немного отличаться, но все API-интерфейсы одинаковы.

Изучение того, как это сделать, - это то, что должен делать каждый iOS-разработчик.

Ответ 2

Мне удалось создать образец приложения, в котором есть центр в центре, который вы можете вращать с помощью UIRotationGestureRecognizer, и скорость вращения будет зависеть от скорости вращения. Я использовал UIDynamics для этого:

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)
    }

}
 }

Когда вы запустите, вы сможете вращать представление в зависимости от скорости вращения.

Ответ 3

Используйте UIPanGestureRecognizer. Создайте panGestureRecognizer и добавьте его в свой контроль над бутылкой и выполните его делегирование. Он имеет переменные, такие как velocityInView, translationInView. Когда пользователь заканчивает панорамирование, используйте их для расчета угла, скорости и продолжительности вращения.