iOS 11 animated gif display in UIImageView - ios

I thought iOS 11 was supposed to bring, at long last, native support for animated gifs? But I tried this, and I didn't see any animation:
let im = UIImage(named:"wireframe.gif")!
let iv = UIImageView(image:im)
iv.animationImages = [im] // didn't help
iv.frame.origin = CGPoint(0,100)
iv.frame.size = im.size
self.view.addSubview(iv)
delay(2) {
iv.startAnimating() // nope
}
How is this supposed to work?

iOS 11 does bring a native understanding of animated gifs, but that understanding, infuriatingly, is not built into UIImageView. It is still up to you to translate the animated gif into a sequence of UIImages. Apple now provides sample code, in terms of the ImageIO framework:
https://developer.apple.com/library/content/samplecode/UsingPhotosFramework/Listings/Shared_AnimatedImage_swift.html
That code implements an AnimatedImage class, which is essentially a collection of CGImages extracted from the original animated gif. Thus, using that class, we can display and animate the animated gif in a UIImageView as follows:
let url = Bundle.main.url(forResource: "wireframe", withExtension: "gif")!
let anim = AnimatedImage(url: url)!
var arr = [CGImage]()
for ix in 0..<anim.frameCount {
arr.append(anim.imageAtIndex(index: ix)!)
}
var arr2 = arr.map {UIImage(cgImage:$0)}
let iv = UIImageView()
iv.animationImages = arr2
iv.animationDuration = anim.duration
iv.frame.origin = CGPoint(0,100)
iv.frame.size = arr2[0].size
self.view.addSubview(iv)
delay(2) {
iv.startAnimating()
}

Unfortunately, the inter-frame timing of a GIF can vary between frames, so answers that use ImageIO to load the frames and then set them as the animatedImages on a UIImageView need to properly extract the timings and take them into account.
I recommend Flipboard's FLAnimatedImage, which handles GIFs correctly.
https://github.com/Flipboard/FLAnimatedImage.

Related

iOS Simulators doesnt render layer as real device

On my iOS app I use a Google Maps view with a GMSLayer, the transparency renders correctly on a real device but the background is white on Simulator, I can't make the screenshots for the App Store...
And this is the code I use :
// Implement GMSTileURLConstructor
// Returns a Tile based on the x,y,zoom coordinates, and the requested floor
let urls: GMSTileURLConstructor = {(x, y, zoom) in
let url = "http://wxs.ign.fr/[KEY]/geoportail/wmts?LAYER=TRANSPORTS.DRONES.RESTRICTIONS&FORMAT=image/png&SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&STYLE=normal&TILEMATRIXSET=PM&TILEMATRIX=" + String(zoom) + "&TILEROW="+String(y)+"&TILECOL="+String(x)
return URL(string: url)
}
// Create the GMSTileLayer
let layer = GMSURLTileLayer(urlConstructor: urls)
layer.zIndex = 0
layer.map = mapView
class TestTileLayer: GMSSyncTileLayer {
override func tileFor(x: UInt, y: UInt, zoom: UInt) -> UIImage {
let url = URL(string : "http://wxs.ign.fr/[KEY]/geoportail/wmts?LAYER=TRANSPORTS.DRONES.RESTRICTIONS&FORMAT=image/png&SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&STYLE=normal&TILEMATRIXSET=PM&TILEMATRIX=" + String(zoom) + "&TILEROW="+String(y)+"&TILECOL="+String(x))
return UIImage(data: try! Data(contentsOf: url!))!
}
}
I'm sure the image given by the URL uses transparency and I tried to manually change the white pixel to transparent but it doesn't change anything...
This is a simulator problem only it has been mentioned here.
However as #a.munzer suggested some work around you can take a screenshot from a real device and just edit it, shouldn't be that much of a problem.

Enumerate through UIImageView

In SpriteKit you are able to enumerate through each node with a specific name. Say I have 10 sprites with the name property set to "foo" I can then run the code below and it will move each "food" node up 5 pixels every time the function is called.
enumerateChildNodesWithName("foo"){node, stop in
let sprite:SKSpriteNode = node as! SKSpriteNode
sprite.position.x += 5
}
Now, I would like to do this with UIImageView (if possible).
Here's my current setup
In my app I have code that runs every second. It is supposed to add a UIImageView using the following code
var mView:UIImageView = UIImageView(image: UIImage(named: "swirl"))
self.view.addSubview(mView)
Finally, I have a for loop that doesn't seem to be targeting each specific view. But it should be moving each individual image view in a circle. Currently it only looks like a single image is moving even while I think I've added more image views.
for view in self.view.subviews as [UIView] {
if let ind = view as? UIImageView {
let OrCe:CGPoint = mView.center
mView.center = CGPoint(x: OrCe.x + sin(tick)*50,
y: OrCe.y + cos(tick)*50)
}
}
I feel like what I'm doing is really wrong :( Is it possible for me to do what I am trying to do? I would like to do this so that I do not have to use SpriteKit. I want to try and create graphics at a lower level framework. Can I go lower then this even? How can I most efficiently render these 10 moving images?
I assume all the two peaces are consecutive.
var mView:UIImageView = UIImageView(image: UIImage(named: "swirl"))
self.view.addSubview(mView)
for view in self.view.subviews as [UIView] {
if let ind = view as? UIImageView {
let OrCe:CGPoint = view.center
view.center = CGPoint(x: OrCe.x + sin(tick)*50,
y: OrCe.y + cos(tick)*50)
}
}
If got you correct this should work.

Load Animated gif in UIImageView IOS

I have this gif into my assets file
The name of the assets is loading_apple but when I add the following code I get a nullpointer exception error:
let img = UIImage (named: "loading_apple")
So how can I show this gif ? :(
Hope someone can help me.
I would recommend using FLAnimatedImage https://github.com/Flipboard/FLAnimatedImage
I would recommend breaking out the frames of that gif and use animatedImageNamed:duration: - you can name them all the similar name with a number change at the end. For instance:
loading-1.png
loading-2.png
loading-3.png etc.
Xcode will recognize you want multiple images and will play those through in order.
Look at THIS
instead of storing the gif file, why don't u make use of CAReplicatorLayer refer this link and this link in objective c, i took same code in second like and with some modification,
func spinTheCustomSpinner() -> Void {
let aBar:CALayer = CALayer.init()
aBar.bounds = CGRectMake(0, 0, 8, 25);
aBar.cornerRadius = 4; //(8/2)
aBar.backgroundColor = UIColor.blackColor().CGColor
aBar.position = CGPointMake(150.0, 150.0 + 35)
let replicatorLayer:CAReplicatorLayer = CAReplicatorLayer.init()
replicatorLayer.bounds = CGRectMake(0, 0,300,300)
replicatorLayer.cornerRadius = 10.0
replicatorLayer.backgroundColor = UIColor.whiteColor().CGColor
replicatorLayer.position = CGPointMake(CGRectGetMidX(self.view!.bounds), CGRectGetMidY(self.view!.bounds))
let angle:CGFloat = CGFloat (2.0 * M_PI) / 12.0
let transform:CATransform3D = CATransform3DMakeRotation(angle, 0, 0, 1.0)
replicatorLayer.instanceCount = 12
replicatorLayer.instanceTransform = transform
replicatorLayer .addSublayer(aBar)
self.view!.layer .addSublayer(replicatorLayer)
aBar.opacity = 0.0
let animationFade:CABasicAnimation = CABasicAnimation(keyPath: "opacity")
animationFade.fromValue = NSNumber(float: 1.0)
animationFade.toValue = NSNumber(float: 0.0)
animationFade.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animationFade.repeatCount = HUGE
animationFade.duration = 1.0
let aBarAnimationDuration:Double = 1.0/12.0
replicatorLayer.instanceDelay = aBarAnimationDuration
aBar .addAnimation(animationFade, forKey: "fadeAnimation")
}
if u use above with a view, show this view while loading and hide after loading, this is really cool and handy and there is no headache of storing the gif file and using a image view to load.
and by changing the properties of aBar layer u get different effects.
For this specific gif you may want to use UIActivityIndicatorView and make it animating with startAnimating()

Animation by PNG frames

I have several PNG images that if it will be presented one after the other they will create a short animation.
My question is -
Is possible to create an animation with several PNG images, by displaying them one after the other?
Yes you can create animation with pngs,
let animationImagesArray : [UIImage] = [<Add images>]
imageView.animationImages = animationImagesArray
imageView.startAnimating()
You can also set repeat count and animation duration as well.
Update
To load sequence of images via loop its better you name them in a sequence some thing like this (animationImage1.png, animationImage2.png...)
for i in 0..<20
{
let name = "\(prefix)_\(i).png"
let image = UIImage(named: name)!
images.append(image)
}

Scenekit Grouped Animations

I am trying to extract animations from one DAE file that contains a few animations. I want to break up the animation in groups so I can play specific animations in the timeline.
I am using the "skinning" slide from the WWDC as a reference, but it is all in objective-c and I think something has been lost in translation when trying to do this in swift.
I have my character loaded in the scene but when i run this code the animation does not run. Whats going on?
for animationID in animationsIDs {
if let animation = sceneSource.entryWithIdentifier(animationID, withClass: CAAnimation.self) as? CAAnimation {
var maxDuration = max(maxDuration, animation.duration);
longAnimations.append(animation)
}
let longAnimationsGroup = CAAnimationGroup()
longAnimationsGroup.animations = longAnimations
longAnimationsGroup.duration = maxDuration
let idleAnimationGroup :CAAnimationGroup = longAnimationsGroup.copy() as CAAnimationGroup
idleAnimationGroup.timeOffset = 0.0
_idleAnimationGroup.animations = [idleAnimationGroup]
_idleAnimationGroup.duration = 1.0
_idleAnimationGroup.repeatCount = FLT_MAX
_idleAnimationGroup.autoreverses = true
SCNTransaction.begin()
self._character.addAnimation(_idleAnimationGroup, forKey: "animation")
SCNTransaction.commit()
it seems that your for loop is missing a closing bracket. Currently you are adding (and thus overriding) an animation with the key "animation" for each animationID
how and where is _idleAnimationGroup created?

Resources