AnimateWithDuration does not have a completion block, WatchOS 2

WatchOS 2 has no completion block in its animateWithDuration function. I am working on a game that requires code to run after the animation is complete. Is there any work around? Perhaps using key monitoring? An alternative would be to use a timer that matches the length of the animation, but is not ideal for obvious reasons.

+4
source share
3 answers

NSOperation did not work for me either. For now, I just use the following solution until Apple officially adds a completion block. Not perfect, but it works. I opened the Radar. Apple may add a block of completion in the future seed of watchOS 2.

animateWithDuration, . .

extension WKInterfaceController {
    func animateWithDuration(duration: NSTimeInterval, animations: () -> Void, completion: (() -> Void)?) {
        animateWithDuration(duration, animations: animations)
        let completionDelay = dispatch_time(DISPATCH_TIME_NOW, Int64(duration * Double(NSEC_PER_SEC)))
        dispatch_after(completionDelay, dispatch_get_main_queue()) {
            completion?()
        }
    }
}
+6

animateWithDuration WKInterfaceController

Obj-C ( @PunnetSethi):

- (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(void))completion{

    [self animateWithDuration:duration animations:animations];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), completion);

}

๏ฃฟWatch WatchOS2

+2

Swift 4

advanced animation method () for watchOS :

  • Duplicate
  • Reversible
  • Stoppable
  • with completion block

import Foundation
import WatchKit



protocol Animatable: class {

func animate(forKey key: String,duration: TimeInterval, repeatCount count: CGFloat, autoreverses: Bool, animations: @escaping () -> Void, reverseAnimations: (() -> Void)?, completion: (() -> Void)?)
func stopAnimations()
}

extension Animatable {

func animate(forKey key: String, duration: TimeInterval, repeatCount count: CGFloat, autoreverses: Bool, animations: @escaping () -> Void, reverseAnimations: (() -> Void)?, completion: (() -> Void)?) {}

func stopAnimations() {}
}

extension WKInterfaceController: Animatable {

private struct AssociatedKeys {
    static var animsDesc = "_animsDesc"
    static var stopDesc = "_stopDesc"
}

var animations: [String: (() -> Void)?] {
    get {return objc_getAssociatedObject(self, &AssociatedKeys.animsDesc) as? [String: (() -> Void)?] ?? [:]}
    set {objc_setAssociatedObject(self, &AssociatedKeys.animsDesc, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)}
}

var animationStopStates: [String: Bool] {
    get {return objc_getAssociatedObject(self, &AssociatedKeys.stopDesc) as? [String: Bool] ?? [:]}
    set {objc_setAssociatedObject(self, &AssociatedKeys.stopDesc, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)}
}

func animate(forKey key: String, duration: TimeInterval, repeatCount count: CGFloat = 1.0, autoreverses: Bool = false, animations: @escaping () -> Void, reverseAnimations: (() -> Void)? = nil, completion: (() -> Void)? = nil) {
    let isStopped = self.animationStopStates[key] ?? false
    if isStopped {
        completion?()
        return
    }
    self.setAnimations(key, reverse: reverseAnimations)
    let count = count - 1
    let deadline = DispatchTime.now() + duration
    self.animate(withDuration: duration, animations: animations)
    DispatchQueue.main.asyncAfter(deadline: deadline) {
        var deadline2 = DispatchTime.now()
        if autoreverses, let rev = reverseAnimations {
            self.animate(withDuration: duration, animations: rev)
            deadline2 = DispatchTime.now() + duration
        }
        DispatchQueue.main.asyncAfter(deadline: deadline2, execute: {
            if !count.isEqual(to: .infinity) && count <= 0 {
                completion?()
            } else {
                self.animate(forKey: key, duration: duration, repeatCount: CGFloat(count), autoreverses: autoreverses, animations: animations, reverseAnimations: reverseAnimations, completion: completion)
            }
        })
    }
}


/// Stops all the currently playing animations
func stopAnimations() {
    for key in self.animations.keys {
        guard let rev = self.animations[key] else {return}
        self.animationStopStates[key] = true
        self.animate(forKey: key, duration: 0, repeatCount: 0, autoreverses: false, animations: {}, reverseAnimations: rev)
    }
    self.animations.removeAll()
}


private func setAnimations(_ key: String, reverse: (() -> Void)?) {
    if self.animations[key] == nil {
        self.animations[key] = reverse
    }

}
}

How to use:

self.animate(forKey: "custom_anim1", duration: 1.0, repeatCount: .infinity, autoreverses: true, animations: {[unowned self] in
        self.myButton.setHeight(100)
    }, reverseAnimations: { [unowned self] in
        self.myButton.setHeight(120)
    }) {
        print("Animation stopped!")
    }

To stop all animations:

self.stopAnimations()
0
source

All Articles