2017-01-12 1 views
2

私は、stackoverflowの他のポストに触発され、少なくともスピンしている運命のホイールを実装しています。現在、私の問題は、画像の右端を下方向にスワイプすると、ホイールが間違った方向に回転することです。運命のホイールを実装する

誰かが間違っているのを見ることができますか?

class WOFView: UIView { 

@IBOutlet weak var wheelImage: UIImageView! 
private var history = [Dictionary<String, Any>]() 
private var rotation: CGFloat = 0 
private var startAngle: CGFloat = 0 
private var circleRotationOffset: CGFloat = 0 


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
    super.touchesBegan(touches, with: event) 

    if let touchPoint = touches.first?.location(in: self){ 
     startAngle = atan2(self.frame.width - touchPoint.y, self.frame.height - touchPoint.x) 
     rotation = startAngle 
     history.removeAll() 
    } 
} 


override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 
    super.touchesMoved(touches, with: event) 

    guard let touchPoint = touches.first?.location(in: self) else { 
     return 
    } 

    let dic = ["time" : NSNumber(value: CFAbsoluteTimeGetCurrent()), 
       "point": NSValue(cgPoint: touchPoint), 
       "rotation": NSNumber(value: Float(circleRotationOffset + rotation))] 

    history.insert(dic, at: 0) 
    if history.count == 3{ 
     history.removeLast() 
    } 

    rotation = atan2(self.frame.width - touchPoint.y, self.frame.height - touchPoint.x) - startAngle 
    wheelImage.transform = CGAffineTransform(rotationAngle: circleRotationOffset + rotation) 
} 


override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { 
    super.touchesEnded(touches, with: event) 

    guard let touchPoint = touches.first?.location(in: self) else { 
     return 
    } 

    guard let lastObject = history.last else{ 
     return 
    } 

    guard let pointValue = lastObject["point"] as? CGPoint else{ 
     return 
    } 

    guard let timeValue = lastObject["time"] as? NSNumber else { 
     return 
    } 

    guard let rotationValue = lastObject["rotation"] as? NSNumber else { 
     return 
    } 

    let timeDif = CFAbsoluteTimeGetCurrent() - (timeValue.doubleValue) 
    circleRotationOffset = circleRotationOffset + rotation 
    let lastRotation = rotationValue.floatValue 

    let dist = sqrt(((pointValue.x - touchPoint.x) * (pointValue.x - touchPoint.x)) + 
     ((pointValue.y - touchPoint.y) * (pointValue.y - touchPoint.y))) 

    let strength = max(Double(min(1.0, dist/80.0)) * (timeDif/0.25) * M_PI * 2, 0.3) * 30 
    print("S: \(strength)") 

    let p = circleRotationOffset 
    let dif = circleRotationOffset - CGFloat(lastRotation) 
    var inc = dif > 0 

    if dif > 3 || dif < -3{ 
     inc = !inc 
    } 


    if (inc){ 
     circleRotationOffset += CGFloat(strength) 
    }else{ 
     circleRotationOffset -= CGFloat(strength) 
    } 

    let anim = CAKeyframeAnimation(keyPath: "transform.rotation.z") 
    anim.duration = max(strength/2, 1.0) 
    anim.isCumulative = true 
    anim.values = [NSNumber(value: Float(p)), Float(circleRotationOffset)] 
    anim.keyTimes = [NSNumber(value: Float(0)),NSNumber(value: Float(1.0))] 
    anim.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)] 
    anim.isRemovedOnCompletion = false 
    anim.fillMode = kCAFillModeForwards 

    wheelImage.layer.removeAllAnimations() 
    wheelImage.layer.add(anim, forKey: "rotate") 
} 

}

EDIT 私はUIPanGestureRecognizerで物事を単純化し、結果を共有したい:

enum SpinningDirection{ 

     case clockwise 
     case antiClockwise 
    } 

    enum MajorDirection{ 
     case up 
     case down 
     case left 
     case right 
    } 

    enum Quadrant{ 
     case ul 
     case ur 
     case ll 
     case lr 
    } 

    class WOFView: UIView, CAAnimationDelegate { 

     @IBOutlet weak var wheelImage: UIImageView! 

     private var maxSpeed = 0 
     private var majorDirection = MajorDirection.right 
     private var quadrant = Quadrant.ul 
     private var spinningDirection = SpinningDirection.clockwise 
     private var winner = "" 

     func setup(){ 

      let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.respondToPanGesture)) 
      addGestureRecognizer(panGesture) 
     } 


     func respondToPanGesture(gesture: UIPanGestureRecognizer){ 

      let velocity = gesture.velocity(in: self) 

      let vX = abs(velocity.x) 
      let vY = abs(velocity.y) 
      let speed = Int(vX + vY) 

      if speed > maxSpeed{ 
       maxSpeed = speed 
      } 

      let location = gesture.location(in: self) 

      if vX > vY{ 
       majorDirection = (velocity.x > 0) ? .right : .left 
      } 
      else{ 
       majorDirection = (velocity.y > 0) ? .down : .up 
      } 

      if location.x < self.frame.width/2 { 
       quadrant = (location.y < self.frame.height/2) ? .ul : .ll 
      } 
      else { 
       quadrant = (location.y < self.frame.height/2) ? .ur : .lr 
      } 

      switch quadrant { 
      case .ul: 

       switch majorDirection { 
       case .down, .left: 
        spinningDirection = .antiClockwise 
       case .up, .right: 
        spinningDirection = .clockwise 
       } 

      case .ur: 

       switch majorDirection { 
       case .down, .right: 
        spinningDirection = .clockwise 
       case .up, .left: 
        spinningDirection = .antiClockwise 
       } 

      case .lr: 

       switch majorDirection { 
       case .down, .left: 
        spinningDirection = .clockwise 
       case .up, .right: 
        spinningDirection = .antiClockwise 
       } 

      case .ll: 
       switch majorDirection { 
       case .down, .right: 
        spinningDirection = .antiClockwise 
       case .up, .left: 
        spinningDirection = .clockwise 
       } 
      } 



      if gesture.state == .began{ 
       maxSpeed = 0 
       self.isUserInteractionEnabled = false 
      } 

      if gesture.state == .ended{ 
       print("Ended") 

       print("MaxSpeed: \(maxSpeed)") 
       print("direction: \(spinningDirection)") 

       startAnimation(speed: maxSpeed, direction: spinningDirection) 
      } 
     } 


     private func startAnimation(speed: Int, direction : SpinningDirection){ 

      var duration = Double(speed)/10 
      if duration > 10{ 
       duration = 10 
      } 
      if duration < 3{ 
       duration = 3 
      } 

      print("duration: \(duration)") 

      let multiplier = (direction == .clockwise) ? -1.0 : 1.0 
      let normalizedSpeed = Double(speed)/10 * multiplier 

      let goal = Double((speed * 100) % Int(2 * Double.pi * 100))/100.0 
      print("goal: \(goal)") 

      let halfPi = Double.pi/2 
      switch goal { 

      case 0*halfPi...1*halfPi: 
       winner = "1" 
      case 1*halfPi...2*halfPi: 
       winner = "4" 
      case 2*halfPi...3*halfPi: 
       winner = "3" 
      case 3*halfPi...4*halfPi: 
       winner = "2" 

      default: 
       print("?") 
      } 

      let anim = CAKeyframeAnimation(keyPath: "transform.rotation.z") 
      anim.duration = duration 
      anim.isCumulative = true 
      anim.values = [NSNumber(value: Float(normalizedSpeed)), Float(goal)] 
      anim.keyTimes = [NSNumber(value: Float(0)),NSNumber(value: Float(1))] 
      anim.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)] 
      anim.isRemovedOnCompletion = false 
      anim.fillMode = kCAFillModeForwards 
      anim.delegate = self 
      wheelImage.layer.removeAllAnimations() 
      wheelImage.layer.add(anim, forKey: "rotate") 
     } 


     func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { 
      print("The winner is \(winner)") 
      self.isUserInteractionEnabled = true 
     } 
    } 
+0

? – shallowThought

+0

今はありません。どのようにこれを行うにはどのようなアイデア?私のイメージは円です。 – netshark1000

答えて

0

がタッチされた側を見つけるための方法を紹介:

func touch(_ touch:UITouch, isInLeftHalfOf view: UIView) -> Bool { 
    let positionInView = touch.location(in: view) 

    return positionInView.x < view.frame.midX 
} 

それが左側でない場合は回転を反転:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 
    // your code ... 

    rotation = atan2(self.frame.width - touchPoint.y, self.frame.height - touchPoint.x) - startAngle 

    if !touch(touches.first!, isInLeftHalfOf: wheelImage) { 
     rotation = -rotation 
    } 
    wheelImage.transform = CGAffineTransform(rotationAngle: circleRotationOffset + rotation) 
} 

をしても、これはあなたの質問(上下方向の画像の右側にスワイプ)で述べたような状況を修正し、あなたはおそらく、少なくとも必要がありますいくつかの微調整が、あなたはアイデアを得る。

結果:あなたは左側と右側の間で区別ん

+0

良いアイデア - ありがとうございますが、実際には期待どおりに動作しません。ときどき、私が開始または停止した場所で、間違った方向にジャンプします。それは私の指に従うことが可能ですか? – netshark1000

+0

それは私が細かいチューニングをする意味です。あれは君次第だ :-)。すべてのタッチ変更を取得すると、確実に指の動きを追跡できます。単純なジェスチャーがあなたの要求を満たすかもしれないなら、まず試してみましょう。(4 x 'UISwipeGestureRecognizer'、各方向に1つ) – shallowThought

+0

ありがとう!これは上記の私の例に適用されているのですか、さらに調整を加えましたか?あなたの例では、時計の7から4にスワイプできますか? – netshark1000

関連する問題