tymac tymac - 5 months ago 22
Swift Question

Render As Template Image on an animated WKInterfaceImage

I have a WKInterfaceImage animation with 160 frames. Animation is great. Now I want to add a tint. This SO question mentions the WatchKit tint method using the Render As Template Image option in the Inspector, but it seems it only works on a single static image. It's tinting only the last frame and it's tinting that last frame the color of my tint in the Inspector not my code tint. I have tried Rendering only the first frame and rendering all the frames to no avail.

Do I have to loop through all of them or set a range or incorporate the setTint method inside of the startAnimatingWithImagesInRange method?

enter image description here

rotateButtonImage.setImageNamed("frame")

rotateButtonImage.startAnimatingWithImagesInRange(NSRange(location: 0, length: 159), duration: 1, repeatCount: 1)
rotateButtonImage.setTintColor(UIColor.redColor())


EDIT: So what I did is create an extension. It looks like this.

WKImage+Tint.swift

extension UIImage {

func imageWithTintColor(colorTint : UIColor) -> UIImage {

UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
colorTint.setFill()

let context : CGContextRef = UIGraphicsGetCurrentContext()! as CGContextRef
CGContextTranslateCTM(context, 0, self.size.height)
CGContextScaleCTM(context, 1.0, -1.0)
CGContextSetBlendMode(context, CGBlendMode.Normal)

let rect : CGRect = CGRectMake(0, 0, self.size.width, self.size.height)
CGContextClipToMask(context, rect, self.CGImage)
CGContextFillRect(context, rect)

let newImage : UIImage = UIGraphicsGetImageFromCurrentImageContext() as UIImage
UIGraphicsEndImageContext()

return newImage
}
}


Then in my custom VC in
awakeWithContext
I called:

rotateButtonImage.image = rotateButtonImage.image.imageWithColor(UIColor.redColor())


But for some reason things are not auto-completing. My WKInterfaceImage is called
rotateButtonImage
and I've imported Foundation and WatchKit etc.

Should my extension or function return type be of type
WKInterfaceImage
instead? I tried changing those but got tons of errors.

So I think I found out this extension will not work in WatchKit lol

So you have to use the Inspector method. But it's still the tint is not working on my animation. I think this may be a bug? Single image can use a tint but maybe not multiple frames even though the code is valid.

Answer

SetTintColor is only working when the image contain a single image template, as explained here.

https://developer.apple.com/library/ios/documentation/WatchKit/Reference/WKInterfaceImage_class/index.html#//apple_ref/occ/instm/WKInterfaceImage/setTintColor:

But, actually, there is a way to recolor animatedImage. It isn't performant, and you don't wanna do this with a large set of Images.

 static func animatedImagesWithColor(color: UIColor) -> [UIImage] {
    var animatedImages = [UIImage]()

    (0...60).forEach { imageNumber in
        if let img = UIImage(named: "MyImage\(imageNumber)") {
            UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale);

            let context = UIGraphicsGetCurrentContext()

            color.setFill()

            CGContextTranslateCTM(context, 0, img.size.height);
            CGContextScaleCTM(context, 1.0, -1.0);
            CGContextClipToMask(context, CGRectMake(0, 0, img.size.width, img.size.height), img.CGImage);
            CGContextFillRect(context, CGRectMake(0, 0, img.size.width, img.size.height));

            animatedImages.append(UIGraphicsGetImageFromCurrentImageContext())
            UIGraphicsEndImageContext()

        }
    }

    return animatedImages
}

You use that array this way :

let animation = UIImage.animatedImageWithImages(UIImage.animatedImagesWithColor(.redColor()), duration: 50)
let range = NSRange(location: 0, length: 60)

animationGroup.setBackgroundImage(animation)
animationGroup.startAnimatingWithImagesInRange(range, duration: 50, repeatCount: -1)