2013-01-07 13 views
19

UIViewにアニメーション化されたbackgroundColourを変更することができます。 UISlideViewでは、アニメーション化された値を変更することができます。アニメーション可能なカスタムプロパティを作成する

独自のUIViewサブクラスにカスタムプロパティを追加してアニメーション化できますか?

UIViewの中にCGPathがある場合は、パスの描画率を変更して図面をアニメーションできます。

そのアニメーションをサブクラスにカプセル化できますか?

つまり、UIViewには、円を作成するCGPathがあります。

円がない場合は0%を表します。円がいっぱいの場合は100%を表します。私はパスの描画率を変更することによって任意の値を描画できます。また、CGPathのパーセンテージをアニメーション化し、パスを再描画することによって(UIViewサブクラス内で)変更をアニメーション化することもできます。

UIViewに何らかのプロパティ(つまりパーセンテージ)を設定して、変更をUIView animateWithDurationブロックに貼り付けることができ、パスの割合の変化をアニメーション化できますか?

私は私がうまくやりたいことを説明してくれることを願っています。

基本的に、私がやりたいすべてが...

[UIView animateWithDuration:1.0 
animations:^{ 
    myCircleView.percentage = 0.7; 
} 
completion:nil]; 

何かのようで、円のパスは、指定された割合をアニメーション化します。

答えて

22

をチェックアウト:

+ (BOOL) needsDisplayForKey:(NSString *) key { 
    if ([key isEqualToString:@"percentage"]) { 
     return YES; 
    } 
    return [super needsDisplayForKey:key]; 
} 

もちろん、percentageと呼ばれる@propertyも必要です。これ以降、コアアニメーションを使用してパーセンテージプロパティをアニメートできます。私もそれが[UIView animateWithDuration...]コールを使って動作しているかどうかを確認しませんでした。それはうまくいくかもしれない。しかし、これは私の仕事:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"percentage"]; 
animation.duration = 1.0; 
animation.fromValue = [NSNumber numberWithDouble:0]; 
animation.toValue = [NSNumber numberWithDouble:100]; 

[myCustomLayer addAnimation:animation forKey:@"animatePercentage"]; 

ああ、これ行う、myCircleViewyourCustomLayerを使用するために:私がやったように、その上でより多くの細部を必要とするものについて

[myCircleView.layer addSublayer:myCustomLayer]; 
+0

返事をありがとう。私は今夜​​見てみましょう。 – Fogmeister

+0

@ Fogmeisterこんにちは、パーティーに少し遅れました。私たちは ' - (void)drawInContext:(CGContextRef)context'をどのように実装するのですか?これは、新たにカスタマイズされたプロパティが描かれる場所ですか?前もって感謝します。 – Unheilig

+0

@Tomあなたのサンプルでは、​​1に手動で長さを設定します...あなたはどのように期間/カーブ/遅延、など... UIViewAnimationブロックによって提供される把握することができるでしょうか? – Georg

0

あなたはパーセンテージパートを自分で実装する必要があります。レイヤー描画コードをオーバーライドして、設定されたパーセンテージ値に基づいてcgpathを描画することができます。あなたはCALayerのを拡張し、あなたがこのように(カスタムCALayerのクラスで)needsDisplayForKeyをオーバーライドすることで、アニメーション化プロパティを作ることができ、カスタム

- (void) drawInContext:(CGContextRef) context 

を実装する場合core animation programming guideanimation types and timing guide

+0

返信いただきありがとうございます。私は今夜​​見てみましょう。 – Fogmeister

+0

なぜdownvote?そんなに長い時間が過ぎても? – lukya

+0

いいえ、考えられません。私とは関係ありません。 – Fogmeister

3

を:

ありこの質問をカバーする涼しいexample from Apple

など。そのおかげで、実際にサブレイヤとしてカスタムレイヤーを追加する必要はないことが分かりました(@Tom van Zummerenが示唆しているように)。代わりに、Viewクラスにクラスメソッドを追加するだけで十分です:

+ (Class)layerClass 
{ 
    return [CustomLayer class]; 
} 

誰かに役立つことを願っています。

7

コンプリート・スウィフト3例:

Final product

public class CircularProgressView: UIView { 

    public dynamic var progress: CGFloat = 0 { 
     didSet { 
      progressLayer.progress = progress 
     } 
    } 

    fileprivate var progressLayer: CircularProgressLayer { 
     return layer as! CircularProgressLayer 
    } 

    override public class var layerClass: AnyClass { 
     return CircularProgressLayer.self 
    } 


    override public func action(for layer: CALayer, forKey event: String) -> CAAction? { 
     if event == #keyPath(CircularProgressLayer.progress), 
      let action = action(for: layer, forKey: #keyPath(backgroundColor)) as? CAAnimation { 

      let animation = CABasicAnimation() 
      animation.keyPath = #keyPath(CircularProgressLayer.progress) 
      animation.fromValue = progressLayer.progress 
      animation.toValue = progress 
      animation.beginTime = action.beginTime 
      animation.duration = action.duration 
      animation.speed = action.speed 
      animation.timeOffset = action.timeOffset 
      animation.repeatCount = action.repeatCount 
      animation.repeatDuration = action.repeatDuration 
      animation.autoreverses = action.autoreverses 
      animation.fillMode = action.fillMode 
      animation.timingFunction = action.timingFunction 
      animation.delegate = action.delegate 
      self.layer.add(animation, forKey: #keyPath(CircularProgressLayer.progress)) 
     } 
     return super.action(for: layer, forKey: event) 
    } 

} 



/* 
* Concepts taken from: 
* https://stackoverflow.com/a/37470079 
*/ 
fileprivate class CircularProgressLayer: CALayer { 
    @NSManaged var progress: CGFloat 
    let startAngle: CGFloat = 1.5 * .pi 
    let twoPi: CGFloat = 2 * .pi 
    let halfPi: CGFloat = .pi/2 


    override class func needsDisplay(forKey key: String) -> Bool { 
     if key == #keyPath(progress) { 
      return true 
     } 
     return super.needsDisplay(forKey: key) 
    } 

    override func draw(in ctx: CGContext) { 
     super.draw(in: ctx) 

     UIGraphicsPushContext(ctx) 

     //Light Grey 
     UIColor.lightGray.setStroke() 

     let center = CGPoint(x: bounds.midX, y: bounds.midY) 
     let strokeWidth: CGFloat = 4 
     let radius = (bounds.size.width/2) - strokeWidth 
     let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: twoPi, clockwise: true) 
     path.lineWidth = strokeWidth 
     path.stroke() 


     //Red 
     UIColor.red.setStroke() 

     let endAngle = (twoPi * progress) - halfPi 
     let pathProgress = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle , clockwise: true) 
     pathProgress.lineWidth = strokeWidth 
     pathProgress.lineCapStyle = .round 
     pathProgress.stroke() 

     UIGraphicsPopContext() 
    } 
} 

let circularProgress = CircularProgressView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) 
UIView.animate(withDuration: 2, delay: 0, options: .curveEaseInOut, animations: { 
    circularProgress.progress = 0.76 
}, completion: nil) 

これは

のと同様にObjCプロジェクトどのように機能するかについての詳細に入る偉大にObjC記事hereは、ありますhere

オブジェクトがアニメーションブロックからアニメートされているときは、基本的にaction(layer :)が呼び出されます。同じプロパティ(backgroundColorプロパティから盗まれた)で独自のアニメーションを開始し、変更をアニメーションできます。

関連する問題