2017-03-10 6 views
0

私は、UITouchイベントから描画ハンドラに記録された一連のポイントを再生しようとしています。最後の1秒後に0.1秒後に各点を描きたい。いったんCGPointの配列を取得すると、配列を反復処理し、GDCのdispatchAfterをキューに入れ、その点で描画メソッドを呼び出します。複数のasyncAfterを互いに対してキューする - Swift 3

override func replay(_ queue: DispatchQueue) { 

    isReplaying = true 

    for stroke in strokeHistory { 

     var additionalTime = 0.0 

     for curPoint in stroke.points { 

      DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + additionalTime, execute: { 
       [unowned self, s = stroke, lrp = stroke.lastReplayPoint] in 
       s.lastReplayPoint = lrp 
       switch curPoint.state { 
       case .began: 
        self.strokeBegan(s, atPoint: curPoint) 
       case .changed: 
        self.strokeMoved(s, toPoint: curPoint) 
       case .ended: 
        self.strokeEnded(s, atPoint: curPoint) 
       default : 
        NSLog("Point phase default.") 
       } 
      }) 

      additionalTime = additionalTime + 0.1 
      stroke.lastReplayPoint = curPoint 
     } 
    } 
} 

再生は機能しますが、徐々に速度が低下し、より遅い間隔と遅い間隔で大きなチャンクが描画されます。どのようにしてこれらの点を0.1秒間描画するようにキューに入れることができますか?

答えて

0

可能性のカップルがあります:

  1. それは本当に減速だ場合、全体のパスを毎回撫でている可能性があります。それで、後者のストロークは引き分けが増え、時間がかかります。したがって、レンダリングが遅くなります。

    これは、定期的に画面のスナップショットを作成し、前の画面のスナップショットと新しいパスをレンダリングすることで解決できます。そうすれば、あなたの道はどれくらい長いか制限されます。

  2. また、速度が低下していない可能性がありますが、タイマーをまとめてまとめるだけで済みます(将来はasyncAfterコールがある場合に発生します)。合体すると、全体的なスピードはほぼ一定に保たれるべきですが、それを一緒に合体させて、タイマーにもっと吃音を与えます。

    これを修正するには、リピートタイマーを使用します(これらを一緒に結合することはできません)。また、ワンショット・タイマーを作成する場合は、DispatchSource.TimerFlag.strictを指定して合体をオプトアウトすることができます。


しかし、さらに簡単に、あなたはストロークをアニメーション化するCore Animationのを使って、この問題を完全に回避することができます。後者の点のレンダリングが遅くなるだけでなく、はるかに簡単でアニメーションもスムーズになります。たとえば、あなたがCAShapeLayerに指定したpathを持っている場合、:

let path: UIBezierPath = ... // construct your path any way you want 

let pathLayer = CAShapeLayer() 
pathLayer.strokeColor = UIColor.blue.cgColor 
pathLayer.fillColor = UIColor.clear.cgColor 
pathLayer.lineWidth = 3 
view.layer.addSublayer(pathLayer) 

次に、あなたがそのようにのように、そのパスのストロークをアニメーション化することができます

let stroke = CABasicAnimation(keyPath: "strokeEnd") 
stroke.fromValue = 0.0 
stroke.duration = 1.0    // change this as you see fit, perhaps saving the original time it took to capture the path and using that (or some fraction thereof) when animating the path 
pathLayer.add(stroke, forKey: nil) 

7,200ポイントでパスを持つ利回り、その:

programmatically created path animated

+0

Iは、パス全体またはキャンバスを描画するたびに、バッファCGLayerその最小「汚れにだけ線分わけではありませんビューのdraw()CGContextに「rect」を追加します。私が複数のdispatchAftersをキューに入れずに配列の最初のポイントを取り出し、描画し、配列から削除し、配列までw/delayを繰り返すと、アニメーションは期待どおりに再生されます空です。 –

+1

@TylerWhite - それはそれではない場合、それはおそらく本当に減速していないが、単にタイマを統合することです(これは将来別のタイマーをスケジュールする場合に起こります)、おおよそ同じ速度のアニメーションを生成し、あなたがさらに遠くになるにつれ、ますます吃音するように見えます。 (DispatchSource.TimerFlag.strict'の 'Flags'を使って' DispatchTimerSource'を使用して)合体をオプトアウトするか、別のタイマーではなく、単一の反復 'Timer'またはディスパッチタイマーを使用する方が簡単です。それは合体を防ぐでしょう。 – Rob

+0

タイマーが合体するのはあなたのことでした。 –

関連する問題