2015-04-17 21 views
0

我得到了與https://stackoverflow.com/questions/28275004/uidynamicanimator-stop-reacting-to-uigravitybehavior中所述完全相同的問題。我也無法更好地解釋它。UIDynamicAnimator停止對重力變化作出反應

有誰知道爲什麼UIDynamicAnimator會突然停止將UIGravityBehavior連接到它們的動畫對象/物品?

編輯

我從Big Nerd Ranch

我修改的例子中運行這個例子,只有兩個立方體,使再現錯誤更容易。立方體掉下來,對重力作出反應就好了,但如果你傾斜手機,立方體最終落在拐角處,相互接觸,那麼它會停止任何運動,因此不會對重力行爲產生反應。

我也想知道,如果這是一個Swift問題。也許我應該嘗試在Obj-C中實現此功能,以查看錯誤是否仍然存在。

這裏是例子:

// 
// ViewController.swift 
// Rock Box 
// 
// Created by Steve Sparks on 7/11/14. 
// Copyright (c) 2014 Big Nerd Ranch. All rights reserved. 
// 

import UIKit 
import CoreMotion 

class ViewController: UIViewController { 
    // Most conservative guess. We'll set them later. 
    var maxX : CGFloat = 320; 
    var maxY : CGFloat = 320; 
    let boxSize : CGFloat = 30.0 
    var boxes : Array<UIView> = [] 

    // For getting device motion updates 
    let motionQueue = NSOperationQueue() 
    let motionManager = CMMotionManager() 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     maxX = super.view.bounds.size.width - boxSize; 
     maxY = super.view.bounds.size.height - boxSize; 
     // Do any additional setup after loading the view, typically from a nib. 
     createAnimatorStuff() 
     generateBoxes() 
    } 

    override func viewDidAppear(animated: Bool) { 
     super.viewDidAppear(animated) 
     NSLog("Starting gravity") 
     motionManager.startDeviceMotionUpdatesToQueue(motionQueue, withHandler: gravityUpdated) 
    } 

    override func viewDidDisappear(animated: Bool) { 
     super.viewDidDisappear(animated) 
     NSLog("Stopping gravity") 
     motionManager.stopDeviceMotionUpdates() 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     NSLog("Memory warning") 
     // Dispose of any resources that can be recreated. 
    } 

    func randomColor() -> UIColor { 
     let red = CGFloat(CGFloat(arc4random()%100000)/100000) 
     let green = CGFloat(CGFloat(arc4random()%100000)/100000) 
     let blue = CGFloat(CGFloat(arc4random()%100000)/100000) 

     return UIColor(red: red, green: green, blue: blue, alpha: 0.85); 
    } 

    func doesNotCollide(testRect: CGRect) -> Bool { 
     for box : UIView in boxes { 
      var viewRect = box.frame; 
      if(CGRectIntersectsRect(testRect, viewRect)) { 
       return false 
      } 
     } 
     return true 
    } 

    func randomFrame() -> CGRect { 
     var guess = CGRectMake(9, 9, 9, 9) 

     do { 
      let guessX = CGFloat(arc4random()) % maxX 
      let guessY = CGFloat(arc4random()) % maxY; 
      guess = CGRectMake(guessX, guessY, boxSize, boxSize); 
     } while(!doesNotCollide(guess)) 

     return guess 
    } 

    func addBox(location: CGRect, color: UIColor) -> UIView { 
     let newBox = UIButton(frame: location) 
     newBox.backgroundColor = color 

     view.addSubview(newBox) 
     addBoxToBehaviors(newBox) 
     self.boxes.append(newBox) 
     newBox.tag = Int(arc4random()) 
     newBox.addTarget(self, action:"tapped:", forControlEvents: .TouchUpInside) 
     return newBox 
    } 

    func tapped(sender: UIButton) { 
     println("sender.tag: ", Int(sender.tag)) 
    } 

    func generateBoxes() { 
     for i in 0..<2 { 
      var frame = randomFrame() 
      var color = randomColor() 
      var newBox = addBox(frame, color: color); 
     } 
    } 

    var animator:UIDynamicAnimator? = nil; 
    let gravity = UIGravityBehavior() 
    let collider = UICollisionBehavior() 
    let itemBehavior = UIDynamicItemBehavior() 

    func createAnimatorStuff() { 
     animator = UIDynamicAnimator(referenceView:self.view); 

     gravity.gravityDirection = CGVectorMake(0, 0.8) 
     animator?.addBehavior(gravity) 

     // We're bouncin' off the walls 
     collider.translatesReferenceBoundsIntoBoundary = true 
     animator?.addBehavior(collider) 

     itemBehavior.friction = 0.7 
     itemBehavior.elasticity = 0.1 
     animator?.addBehavior(itemBehavior) 
    } 

    func addBoxToBehaviors(box: UIView) { 
     gravity.addItem(box) 
     collider.addItem(box) 
     itemBehavior.addItem(box) 
    } 

    //----------------- Core Motion 
    func gravityUpdated(motion: CMDeviceMotion!, error: NSError!) { 
     let grav : CMAcceleration = motion.gravity; 

     let x = CGFloat(grav.x); 
     let y = CGFloat(grav.y); 
     var p = CGPointMake(x,y) 

     if (error != nil) { 
      NSLog("\(error)") 
     } 

     // Have to correct for orientation. 
     var orientation = UIApplication.sharedApplication().statusBarOrientation; 

     if(orientation == UIInterfaceOrientation.LandscapeLeft) { 
      var t = p.x 
      p.x = 0 - p.y 
      p.y = t 
     } else if (orientation == UIInterfaceOrientation.LandscapeRight) { 
      var t = p.x 
      p.x = p.y 
      p.y = 0 - t 
     } else if (orientation == UIInterfaceOrientation.PortraitUpsideDown) { 
      p.x *= -1 
      p.y *= -1 
     } 

     var v = CGVectorMake(p.x, 0 - p.y); 
     gravity.gravityDirection = v; 
    } 
} 

EDIT2

我只注意到他們沒有互相接觸,以停止響應UIGravityBehavior。

EDIT3

好,似乎是在斯威夫特的錯誤莫名其妙。我在ObjC中實現了同樣的功能,沒有任何問題。

+0

我想你會更好地發佈一些代碼,以便其他人可以知道什麼是錯的。 – Leo

+0

@WenchenHuang用例子更新。 – user3607973

+0

你有沒有解決這個問題?我在這裏得到相同的問題 – Christos

回答

2

問題是,重力更新會導致在主線程以外的線程上調用gravityUpdated()。你應該保持你的UI更新到主線程。

要解決它,無論是切換到主線程在gravityUpdated(),像這樣:

func gravityUpdated(motion: CMDeviceMotion!, error: NSError!) { 
    dispatch_async(dispatch_get_main_queue()) { 
     // rest of your code here 
    } 
} 

或者在主隊列執行CMMotionManager代替,就像這樣:

此行

let motionQueue = NSOperationQueue() 

變化

let motionQueue = NSOperationQueue.mainQueue() 
相關問題