6

CAGradientLayer을 상상해보십시오.단순히 다른 속성을 변경하는 레이어 속성에 애니메이션을 적용 하시겠습니까?

.startPoint.endPoint을 애니메이션으로 만드는 것은 매우 쉽습니다.

이제 float spinLike을 간단히 으로 설정하면이됩니다.

{대신 두 개의 서로 다른 애니메이션을 필요없이 그래서, 당신은 단순히 spinLike 애니메이션을 수 있습니다.} 그래서

뭔가 같은 ..

class CustomGradientLayer: CAGradientLayer { 

    @objc var spinLike: CGFloat = 0 { 

     didSet { 

      startPoint = CGPoint(...) 
      endPoint = CGPoint(...) 
      setNeedsDisplay() 
     } 
    } 
} 

spinLike 애니메이션 ...

class Test: UIView { 

    ... 
    g = CustomGradientLayer() 
    a = CABasicAnimation(keyPath: "spinLike") 
    ... 
    g.add(a, forKey: nil) 
    ... 

그러나.

작동하지 않습니다. startPointendPoint은 전혀 이동되지 않습니다.

무엇이 잘못 되었나요?


주 - 비극적 인 것 같습니다 당신이 할 수없는 @NSManaged didSet이있는 건물 ...

enter image description here


주 - 당신의 자신의 사용자 지정 애니메이션을 만들 정도로 쉽게은 무승부 루프을 무시합니다.

많은 예가 있습니다. 이것은 당신이 그것을 할 방법 :

class CircleProgressLayer: CALayer { 

    @NSManaged var progress: CGFloat 

    override class func needsDisplayForKey(key: String) -> Bool { 

     if key == "progress" { 
      return true 
     } 
     return super.needsDisplayForKey(key) 
    } 

    override func draw(in ctx: CGContext) { 

     path.fill() etc etc... your usual drawing code 
    } 
} 

불행하게도 내 여기에 질문 실제 도면

관련이 : 재산 spinLike 애니메이션으로

, 단순히 기존의 각 프레임을 변경하려면

일반 애니메이션 속성 (이 예제에서는 .startPoint.endPoint)

어떻게합니까?

참고! 당신은 drawInContext에서 .startPoint.endPoint을 변경할 수 없습니다 - 당신이 attempting to modify read-only layer

+0

당신은 (문맥 : CGContext) 그릴'덮어 쓰기한다 :'가 아니라'drawInContext (CTX : CGContext)'

은 레이어 클래스의 코드입니다. – clemens

+0

(흠, 그게 @clemens가 아니예요. 저는 실제로'draw # in'을 테스트 했었습니다. 저는 방금 이전 습관을 입력했습니다 ... :) – Fattie

+0

문제에 대해 진전을 보았습니까? 'startPoint'와'endPoint'가 항상 'spinLike'와 관련이 있다면,이 속성들을 드롭하고 그 값을'draw (in :)'로 계산할 수 있습니다. – clemens

답변

1

지정 속성을 애니메이션 것, 당신이 @NSManaged로 표시해야한다. 새 값을 지정할 때 강제로 다시 그려서는 안됩니다. 대신 needsDisplay(forKey:)을 덮어 써야합니다.

class CustomedGradLayer: CAGradientLayer { 
    @NSManaged var spinLike: CGFloat 

    class func needsDisplay(forKey key: String) -> Bool { 
     return key == "spinLike" || super.needsDisplay(forKey: key) 
    } 

    class func defaultValue(forKey key: String) -> Any? { 
     return key == "spinLike" ? CGFloat(0) : super.defaultValue(forKey: key) 
    } 
} 

마지막으로 Apple documentation에 따라 레이어의 그림을 구현해야합니다.

몇 달 전에 스위프트에서 작은 프로젝트를 작성했습니다. Koch 커브의 깊이를 가진 커스텀 레이어 애니메이션을 보여줍니다.

class KochLayer: CALayer { 
    fileprivate let kPI = CGFloat(Double.pi) 
    @NSManaged var depth : CGFloat 
    var midPoint: CGPoint { 
     get { 
      let theBounds = self.bounds 

      return CGPoint(x: theBounds.midX, y: theBounds.midY) 
     } 
    } 
    var color: CGColor! 

    override class func defaultValue(forKey inKey: String) -> Any? { 
     return inKey == kDepthKey ? 0.0 : super.defaultValue(forKey: inKey) 
    } 

    override class func needsDisplay(forKey inKey: String) -> Bool { 
     if inKey == kDepthKey { 
      return true 
     } 
     else { 
      return super.needsDisplay(forKey: inKey) 
     } 
    } 

    override init() { 
     super.init() 
    } 

    override init(layer inLayer: Any) { 
     super.init(layer: inLayer) 
     if let theLayer = inLayer as? KochLayer { 
      depth = theLayer.depth 
      color = theLayer.color 
     } 
    } 

    required init(coder inCoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    func pointWithRadius(_ inRadius: CGFloat, angle inAngle: CGFloat) -> CGPoint { 
     let theCenter = midPoint 

     return CGPoint(x: theCenter.x + inRadius * sin(inAngle), 
      y: theCenter.y - inRadius * cos(inAngle)); 
    } 

    override func draw(in inContext: CGContext) { 
     let theBounds = self.bounds 
     let theRadius = fmin(theBounds.width, theBounds.height)/2.0 
     let thePoints: [CGPoint] = [ 
      pointWithRadius(theRadius, angle:0.0), 
      pointWithRadius(theRadius, angle:2 * kPI/3.0), 
      pointWithRadius(theRadius, angle:4 * kPI/3.0) 
     ] 
     let thePath = CGMutablePath() 

     inContext.setLineWidth(0.5) 
     inContext.setLineCap(.round) 
     inContext.setLineJoin(.round) 
     inContext.setFillColor(color) 
     thePath.move(to: thePoints[0]) 
     for i in 0..<3 { 
      addPointsToPath(thePath, fromPoint:thePoints[i], toPoint:thePoints[(i + 1) % 3], withDepth:self.depth) 
     } 
     inContext.addPath(thePath) 
     inContext.fillPath() 
    } 

    func addPointsToPath(_ inoutPath: CGMutablePath, fromPoint inFromPoint: CGPoint, toPoint inToPoint: CGPoint, withDepth inDepth: CGFloat) { 
     var thePoints = Array<CGPoint>(repeating: inFromPoint, count: 5) 

     thePoints[4] = inToPoint; 
     if inDepth <= 1.0 { 
      curveWithWeight(inDepth, points:&thePoints) 
      for i in 1..<5 { 
       inoutPath.addLine(to: thePoints[i]) 
      } 
     } 
     else { 
      let theDepth = inDepth - 1; 

      curveWithWeight(1.0, points:&thePoints) 
      for i in 0..<4 { 
       addPointsToPath(inoutPath, fromPoint:thePoints[i], toPoint:thePoints[i + 1], withDepth:theDepth) 
      } 
     } 
    } 

    func curveWithWeight(_ inWeight: CGFloat, points inoutPoints: inout [CGPoint]) { 
     let theFromPoint = inoutPoints[0] 
     let theToPoint = inoutPoints[4] 
     let theFactor = inWeight/(2 * sqrt(3)) 
     let theDelta = CGSize(width: theToPoint.x - theFromPoint.x, height: theToPoint.y - theFromPoint.y); 

     inoutPoints[1] = CGPoint(x: theFromPoint.x + theDelta.width/3, 
      y: theFromPoint.y + theDelta.height/3) 
     inoutPoints[2] = CGPoint(x: theFromPoint.x + theDelta.width/2 + theFactor * theDelta.height, 
      y: theFromPoint.y + theDelta.height/2 - theFactor * theDelta.width); 
     inoutPoints[3] = CGPoint(x: theToPoint.x - theDelta.width/3, 
      y: theToPoint.y - theDelta.height/3) 
    } 
} 
+0

'CGFloat'는'double'을 기반으로하고 Objective C의 클래스에서는 사용되지 않습니다. 따라서이 옵션은 사용할 수 없습니다. 내 대답에 물음표없이 예제에 따라 선언해야합니다. – clemens

+1

작은 것 (그다지 중요하지 않음) 여기 ... Apple이 CoreData ('The Swift Programming Language/Swift 4/Page 874)와 명시 적으로 연결하기 때문에'동적 인 '이 여기서'@ NSManaged' – Alladinian

+1

@Alladinian 해당 Objective-C 코드는 Swift의 동적 키워드와 다른'@ dynamic'이 될 것이므로 불행하게도'dynamic'은 여기서 작동하지 않습니다. –