使用 UIGestureRecognizer 旋转瓶子

Posted

技术标签:

【中文标题】使用 UIGestureRecognizer 旋转瓶子【英文标题】:Spin bottle with UIGestureRecognizer 【发布时间】:2016-06-22 12:58:21 【问题描述】:

我现在正在使用此代码在点击按钮时旋转瓶子:

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

但是如何使用手势旋转按钮?所以我移动手指越用力/越快,瓶子就会旋转得越快

【问题讨论】:

只是想知道您是否看到我对我的回答的编辑。它现在包含所有能够执行此操作的 swift 代码。 你似乎对此保持沉默。 Just6 检查你是否能正常工作?谢谢 【参考方案1】:

对此的简单回答是……使用UIScrollView

从我这里的问题...Loop UIScrollView but continue decelerating

将它翻译成 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)

在这个例子中,我的旋转视图是arrowViewscrollViewarrowView 都应该是视图控制器视图的子视图。 scrollView 中不应包含任何内容。

注意这是在浏览器中完成的,因此可能存在一些语法问题。您可能还需要将一些数字转换为 CGFloat 等...

此外,能够从 Objective-C 进行翻译对于任何 ios 开发人员来说都是必不可少的。数以百万计的应用程序是使用 Objective-C 编写的。语法可能略有不同,但所有 API 都相同。

了解如何做到这一点是每个 iOS 开发者都应该做的事情。

【讨论】:

你有任何示例代码或任何关于我将如何执行此操作的内容吗? @RoduckNickes 我博客中的示例代码可以用同样的方式使用。您需要做的就是将 contentOffset.x 转换为角度。也许 0=0 和 200=2*Pi 旋转。然后 400=4*Pi 等等……这样,每 200 个滚动点就等于一个完整的旋转。 @RoduckNickes 我查看了我为此编写的代码,但找不到。对不起。我认为这只是我进行的一项实验。 @RoduckNickes 完成。你应该学习如何在 Objective-C 和 Swift 之间进行转换。这是微不足道的和必不可少的。数以百万计的应用程序和价值多年的教程都是用 Objective-C 编写的。 @RoduckNickes 我还建议不要仅复制和粘贴此代码。这样做你什么也学不到,而且很懒惰。看代码。了解它在做什么以及为什么并尝试自己重写它。【参考方案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)
    


 

当您跑步时,您将能够根据旋转手势的速度旋转视图。

【讨论】:

谢谢,但它只向右侧旋转,并且当我移动手指时它不会移动。我必须用两个手指,它需要很长时间才能停止旋转。?有什么想法吗? 您可以在旋转手势中使用旋转角度,这样它就可以在两侧工作。如果你想用一根手指,你可以使用滑动手势,我认为这很容易。对于停止旋转的时间太长,您可以更改幅度值UIPushBehavior 我给了您 while 的想法以及如何做到这一点。它只需要你的一些调整:)【参考方案3】:

使用UIPanGestureRecognizer。创建一个 panGestureRecognizer 并将其添加到您的瓶子的超级视图并实现它的委托。它具有velocityInViewtranslationInView 等变量。当用户完成平移时,使用它们来计算旋转的角度、速度和持续时间。

【讨论】:

好的,因此您创建了平移手势识别器(UIScrollView 免费提供)您创建了捕获速度的方法(UIScrollView 免费提供)您根据视图中的平移更新旋转( UIScrollView 有免费的内容偏移)那么你如何根据用户释放他们的点击的速度计算减速度? UIScrollView 为你做这件事。您在此处描述的所有计算和艰苦工作都是由 UIScrollView 完成的。您所要做的就是获取偏移量并旋转图像。 @Fogmeister 你的contentSize 设置了多少?百万?听起来不对。 我是如何将内容大小设置为任意大的。这是为了确保滚动视图永远不会在单个滚动中结束。但是,当滚动视图不再滚动时,它可以重置为 0(+- 基于角度的偏移量),以便每次旋转停止时它都会返回。有效地使其无限滚动。 好吧,假设你已经破解了它。有一天(比如说未来几年)你想检查一些东西,或者你把你的代码给别人,它会读取你的代码,他就像,为什么是滚动视图?它在滚动吗? scrollView 在哪里?,这就是我要说的。 @Fogmeister 我记得有一个很大的限制(我认为是 99k)。但是如果到达内容的末尾,您的视图将不再正常工作(直到您再次将其设置为零)

以上是关于使用 UIGestureRecognizer 旋转瓶子的主要内容,如果未能解决你的问题,请参考以下文章

转iOS手势识别的详细使用(拖动,缩放,旋转,点击,手势依赖,自定义手势) -- 不错不错

iOS 手势操作:拖动捏合旋转点按长按轻扫自定义

UIGestureRecognizer

使用 UIGestureRecognizer 模拟按钮单击

如何用 UIGestureRecognizer 替换 TouchesBegan

UIGestureRecognizer 从头开始​​制作 UISlider