skyweb07 / Snap.swift

Snapshot testing in a snap 🎨
MIT License
422 stars 19 forks source link

SpriteKit support #30

Open ralfebert opened 6 years ago

ralfebert commented 6 years ago

Snap will render an empty, transparent image for SKViews. As a workaround, checking and handling for Spritekit in UIView+Render seems to do the trick:

if let skview = self as? SKView {
    return UIImage(cgImage: skview.texture(from: skview.scene!)!.cgImage())
}
skyweb07 commented 6 years ago

Ohh that's awesome, I really haven't tried working with SpriteKit, but it could be superb if you could open a PR with a fix, thanks!!!

ralfebert commented 6 years ago

This needs a bit more work, it doesn't seem to capture Retina images. Also I added some code to capture SpriteKit views in the hierarchy via a workaround: it adds an image view with the captured image via the SpriteKit API before capturing the whole view: https://github.com/ralfebert/Snap.swift/commit/b0b020339c510c4f4f6d29c7dcc70d1069021883 It works fine for me, but I think this code needs a bit more testing/polishing.

ralfebert commented 6 years ago

I found that all these cases can be handled easily by using the UIView snapshotView method. It returns a "image" view which can be drawn using drawHierarchy and always shows what a user would see. I am currently using this in UIView+render and it does seem to do the trick.

ralfebert commented 6 years ago

Ahh, big relevation: drawHierarchy works fine! But currently, Snap renders the layer of the view on top of the view in UIView+Render:

    drawHierarchy(in: bounds, afterScreenUpdates: true)
    layer.render(in: context)   // <---

And this breaks capturing views from GLKit, SceneKit and SpriteKit. What is this about / for what is rendering the layer needed / is this not included in drawHierarchy?

ralfebert commented 6 years ago

Ah, drawHierarchy only works when a UIWindow is present, thats why layer.render is there as well.

But I think rendering twice, once using drawHierarchy, then on top of it as a layer isn't correct (I also saw some render glitches due to that).

I am currently working on a pull request to properly capture SpriteKit and SceneKit.

I think always using layer.render() is the way to go, because it also works headless without a host application.