2016-09-14 5 views
9

문제점
I 두 뷰 컨트롤러가이 모두 각각의 UINavigationController 번의 UITabBarController 내에 포함를 사용하여 기각한다. 뷰 컨트롤러 중 하나에서 화면에 거품을 그려서 위치를 애니메이션하는 거품 효과를 만듭니다. 문제는 탭 막대를 사용하여 다른보기 컨트롤러로 이동할 때 발생합니다. 이로 인해 CPU가 스파이크를 일으키고 100 %로 유지되고 거품이 계속 움직입니다.애니메이션은 탭 막대

코드 거품에 대한
코드는 UIView 서브 클래스 내에서 캡슐화된다.

override func draw(_ rect: CGRect) { 
    // spawn shapes 
    for _ in 1 ... 10 { // spawn 75 shapes initially 
     spawn() 
    } 
    } 

drawRect 방법은 반복적으로 거품 뷰를 채우는 spawn 함수를 호출한다.

fileprivate func spawn() { 
    let shape = CAShapeLayer() 
    shape.opacity = 0.0 

    // create an inital path at the starting position 
    shape.path = UIBezierPath(arcCenter: CGPoint.zero, radius: 1, startAngle: 0, endAngle: 360 * (CGFloat.pi/180), clockwise: true).cgPath 
    shape.position = CGPoint.zero 

    layer.addSublayer(shape) 


    // add animation group 
    CATransaction.begin() 

    let radiusAnimation = CABasicAnimation(keyPath: "path") 
    radiusAnimation.fromValue = shape.path 
    radiusAnimation.toValue = UIBezierPath(arcCenter: center, radius: 100, startAngle: 0, endAngle: 360 * (CGFloat.pi/180), clockwise: true).cgPath 

    CATransaction.setCompletionBlock { [unowned self] in 

     // remove the shape 
     shape.removeFromSuperlayer() 
     shape.removeAllAnimations() 

     // spawn a new shape 
     self.spawn() 
    } 

    let movementAnimation = CABasicAnimation(keyPath: "position") 
    movementAnimation.fromValue = NSValue(cgPoint: CGPoint.zero) 
    movementAnimation.toValue = NSValue(cgPoint: CGPoint(x: 100, y: 100)) 


    let animationGroup = CAAnimationGroup() 
    animationGroup.animations = [radiusAnimation, movementAnimation] 
    animationGroup.fillMode = kCAFillModeForwards 
    animationGroup.isRemovedOnCompletion = false 
    animationGroup.duration = 2.0 

    shape.add(animationGroup, forKey: "bubble_spawn") 

    CATransaction.commit() 
    } 

CATransaction 완료 처리기 내에서 수퍼 뷰에서 모양을 제거하고 새 모양을 만듭니다. 나는 removeAllAnimations를 추가하려고했습니다
답변에서

func removeAllAnimationsFromLayer() { 

    layer.sublayers?.forEach({ (layer) in 
     layer.removeAllAnimations() 
     layer.removeFromSuperlayer() 
    }) 

    CATransaction.setCompletionBlock(nil) 
    } 

시도 : self.spawn()에 함수 호출 내가 다음 전화를 포함하는 뷰 컨트롤러의 viewDidDisappear

문제를 것 같다 기능은 UITabBarControllerDelegate입니다.

+0

'completionBlock'에서'self.spawn()'을 제거하면 어떻게됩니까? –

+0

애니메이션이 완료되면 모양이 다시 생성되지 않습니다. 진행중인 애니메이션이 삭제되어 있고 다음 뷰 컨트롤러가 푸시 된 경우 문제가 발생하지 않습니다. – Ollie

+0

'스폰'할지 여부를 제어하는 ​​부울 플래그를 추가 할 수 있습니다. 그냥 생각 : D –

답변

1

에 추가해야합니다. GUI에 영향을주는 모든 것을 주 스레드로 보내고 명시 적으로 새 스레드 인 spawn을 다른 스레드로 보내는 것으로 놀아주세요. 그것이 어떻게되는지보십시오. 다음과 같은 것 :

fileprivate func spawn() { 

    let shape = CAShapeLayer() 
    shape.opacity = 0.0 

    // create an inital path at the starting position 
    shape.path = UIBezierPath(arcCenter: CGPoint.zero, radius: 1, startAngle: 0, endAngle: 360 * (CGFloat.pi/180), clockwise: true).cgPath 
    shape.position = CGPoint.zero 


    // create an inital path at the starting position 
    shape.path = UIBezierPath(arcCenter: startingPosition, radius: startRadius, startAngle: BubbleConstants.StartingAngle, endAngle: BubbleConstants.EndAngle, clockwise: true).cgPath 
    shape.position = startingPosition 

    // set the fill color 
    shape.fillColor = UIColor.white.cgColor 

    layer.addSublayer(shape) 

    shape.opacity = Float(opacity) 

    DispatchQueue.main.async { 
     self.layer.addSublayer(shape) 
     CATransaction.begin() 
    } 

    let radiusAnimation = CABasicAnimation(keyPath: "path") 
    radiusAnimation.fromValue = shape.path 
    radiusAnimation.toValue = UIBezierPath(arcCenter: center, radius: endRadius, startAngle: BubbleConstants.StartingAngle, endAngle: BubbleConstants.EndAngle, clockwise: true).cgPath 


    DispatchQueue.main.async { [unowned self] in 
     CATransaction.setCompletionBlock { [unowned self] in 

      // remove the shape 
      DispatchQueue.main.async { 
       shape.removeFromSuperlayer() 
       shape.removeAllAnimations() 
      } 

      DispatchQueue.global(qos: .background).async { 
       // spawn a new shape 
       self.spawn() 
      } 
     } 
    } 


    let movementAnimation = CABasicAnimation(keyPath: "position") 
    movementAnimation.fromValue = NSValue(cgPoint: startingPosition) 
    movementAnimation.toValue = NSValue(cgPoint: destination) 


    let animationGroup = CustomAnimationGroup() 
    animationGroup.animations = [radiusAnimation, movementAnimation] 
    animationGroup.fillMode = kCAFillModeForwards 
    animationGroup.isRemovedOnCompletion = false 
    animationGroup.duration = duration 

    shape.add(animationGroup, forKey: "bubble_spawn") 

    DispatchQueue.main.async { 
     CATransaction.commit() 
    } 
} 
+0

자세한 답변을 주셔서 감사합니다. 이전에 제안한 내용 중 대부분을 사용하지 않았 음을 인정해야합니다. 스위프트 3.0으로 번역하면서 불행히도 문제가 지속되는 한 최선을 다해 귀하의 제안을 구현하려고했습니다. 스레딩 코드를 올바르게 변환했는지 확인하기 위해 빠른 확인을하는 데 신경 쓸 일이 없더라도 매우 감사 할 것입니다. https://gist.github.com/ollie-eman/3eccd3e015a9774a31696772ef9df817 – Ollie

+0

스위프트 3에 대한 예를 조정했습니다. 이제는 디스패치가 훨씬 편안해졌습니다. :) – RyuX51

+1

@Ollie github에서 제공 한 코드는 DispatchQueue.main.sync가 도움이되지 않는다고 생각합니다. 최소한 DispatchQueue.main.async (async vs sync)를 사용하려고 시도하십시오. – Cristian

0

UITabBarController에서 연관된 뷰 컨트롤러는 평면 구조를가집니다. 즉, 각 탭의보기 컨트롤러는 독립적으로 실행됩니다.

따라서, func removeAllAnimationsFromLayer() 당신이 단지 모든 것들에 대해 하나 개의 스레드를 사용하는 것이, 당신의 문제가 생각하는 대리자 메서드

func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController)

+0

답변 해 주셔서 감사합니다. 문제는 계속됩니다. 내 질문의 맨 아래에 답변을 구현했습니다. 내가 잘못 구현 한 경우 큰 소리로 말하십시오 – Ollie