使用 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)
在这个例子中,我的旋转视图是arrowView
。 scrollView
和 arrowView
都应该是视图控制器视图的子视图。 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 并将其添加到您的瓶子的超级视图并实现它的委托。它具有velocityInView
、translationInView
等变量。当用户完成平移时,使用它们来计算旋转的角度、速度和持续时间。
【讨论】:
好的,因此您创建了平移手势识别器(UIScrollView 免费提供)您创建了捕获速度的方法(UIScrollView 免费提供)您根据视图中的平移更新旋转( UIScrollView 有免费的内容偏移)那么你如何根据用户释放他们的点击的速度计算减速度? UIScrollView 为你做这件事。您在此处描述的所有计算和艰苦工作都是由 UIScrollView 完成的。您所要做的就是获取偏移量并旋转图像。 @Fogmeister 你的contentSize
设置了多少?百万?听起来不对。
我是如何将内容大小设置为任意大的。这是为了确保滚动视图永远不会在单个滚动中结束。但是,当滚动视图不再滚动时,它可以重置为 0(+- 基于角度的偏移量),以便每次旋转停止时它都会返回。有效地使其无限滚动。
好吧,假设你已经破解了它。有一天(比如说未来几年)你想检查一些东西,或者你把你的代码给别人,它会读取你的代码,他就像,为什么是滚动视图?它在滚动吗? scrollView 在哪里?,这就是我要说的。
@Fogmeister 我记得有一个很大的限制(我认为是 99k)。但是如果到达内容的末尾,您的视图将不再正常工作(直到您再次将其设置为零)以上是关于使用 UIGestureRecognizer 旋转瓶子的主要内容,如果未能解决你的问题,请参考以下文章
转iOS手势识别的详细使用(拖动,缩放,旋转,点击,手势依赖,自定义手势) -- 不错不错