I'm trying to animate images in particular time- duration. It is working fine in Objective C. However, it is not working for Swift, where is my mistake?
The code for Objective-C is -
-(void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *imgListArray=[NSMutableArray array];
for (int i=0; i<=11; i++)
{
NSString *strImageName=[NSString stringWithFormat:#"c%d.png", i];
NSLog(#"%#",strImageName);
UIImage *image=[UIImage imageNamed:strImageName];
[imgListArray addObject:image];
}
self.imgView.animationImages = imgListArray;
self.imgView.animationDuration =1.0f;
[self.imgView startAnimating];
// Do any additional setup after loading the view, typically from a nib
}
The Code for swift is-
override func viewDidLoad()
{
super.viewDidLoad()
var imgListArray :NSMutableArray = []
for countValue in 1...11
{
var strImageName : String = "c\(countValue).png"
var image = UIImage(named:strImageName) // suggested by Anil
imgListArray.addObject(image)
}
// Swift code HERE for Objective c
}
[UIImage imageNamed (strImageName)]
This not swift code. In swift it would be
UIImage(named:strImageName)
Modified code:
var imgListArray :NSMutableArray = []
for countValue in 1...11
{
var strImageName : String = "c\(countValue).png"
var image = UIImage(named:strImageName)
imgListArray .addObject(image)
}
self.imageView.animationImages = imgListArray;
self.imageView.animationDuration = 1.0
self.imageView.startAnimating()
for Swift 2, use [UIImage] instead.
var images: [UIImage] = []
for i in 1...2 {
images.append(UIImage(named: "c\(i)")!)
}
myImageView.animationImages = images
myImageView.animationDuration = 1.0
myImageView.startAnimating()
In swift you can go one step further and have a simple line to do this:
let loadingImages = (1...11).map { UIImage(named: "c\($0)")! }
Then you can do the rest and inject this into an imageView
self.imageView.animationImages = loadingImages
self.imageView.animationDuration = 1.0
self.imageView.startAnimating()
In swift 3 - Create Array of images and just animate that.
func animate_images()
{
let myimgArr = ["1.jpg","2.jpg","3.jpg"]
var images = [UIImage]()
for i in 0..<myimgArr.count
{
images.append(UIImage(named: myimgArr[i])!)
}
imgView_ref.animationImages = images
imgView_ref.animationDuration = 0.04
imgView_ref.animationRepeatCount = 2
imgView_ref.startAnimating()
}
And for stop animation just write
imgView_ref.stopAnimating()
Swift 3+
UIImageViews can animate images in two different ways (the other answers already cover the first way in deep):
Create an [UIImage] array with the images to animate
Set the animationImages property of the view with this array
Set the animationDuration property
Start the animation
Encapsulate the animation in an UIImage using animatedImage(with:duration:)
Set the normal image property of the view
The following code uses #imageLiterals:
let images = [img1, img2, img3] // use of #imageLiterals here
let animation = UIImage.animatedImage(with: images, duration: 1)
self.myImageView.image = animation
Pro:
If you have to change the image of an UIImageView a lot and maybe one of those images should be animated, then you don't have to start/stop the animation every time anymore neither you need to set the animatedImages property back to nil to display the image stored in the image property of the image view.
Con:
You can't start/stop the animation, if it's encapsulated in a single UIImage instead of an array.
More on #imageLiterals:
If you want to use an image literal, either type imageLiteral or just type the name of an image from your assets folder and Xcode's code completion will suggest it.
Further reading:
Another good blog post about using #imageLiterals and #colorLiterals with animations to follow.
another approach if you want to animate an array of images:
var counter = 1
var timer = NSTimer()
#IBOutlet weak var someImg: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: Selector("doSomeAnimation"), userInfo: nil, repeats: true)
}
func doSomeAnimation() {
//I have four pngs in my project, which are named frame1.png ... and so on
if counter == 4 {
counter = 1
}else {
counter++
}
someImg.image = UIImage(named: "frame\(counter).png")
}
Hope it helps!!
For anyone running multiple animations, depending on a variable, try the below.
For example, you could run an animation sending 0 or 1 (maybe based on if your app knows its daytime or nighttime):
func runAnimation (imgView: UIImageView, arrayPos: Int) {
let timingArray = [7.0,10.0] //Durations of each
let frameArray = [43,45] //Frames for each
var imgArray: Array<UIImage> = [] //Setup empty array
for i in 1 ... frameArray[arrayPos] {
//Fill empty array with images!!
let imageToAdd = UIImage(named: "animationNum_\(arrayPos)-frameNum_\(i)")
imgArray.append(imageToAdd!)
}
imgView.animationImages = imgArray
imgView.animationDuration = timingArray[arrayPos]
imgView.animationRepeatCount = 2
imgView.startAnimating()
}
Related
I have the case, where the connect button is pressed, and continuously animated until the VPN has connected. Then I would like to stop the animation and load up a new set of images and animate that only once.
#IBOutlet weak var vpnButton: UIImageView!
var premiumImages: [UIImage] = []
var loadingImages: [UIImage] = []
#objc private func vpnStatusDidChange(_ notification: Notification) {
let nevpnconn = notification.object as! NEVPNConnection
let status = nevpnconn.status
switch status {
case NEVPNStatus.connecting:
self.animateImages(imageView: self.vpnButton, images: loadingImages, duration: 1.0, isInfinite: true)
self.vpnButton.image = UIImage(named: "Red-1")
}
The method that takes care of animation:
func animateImages(imageView: UIImageView, images: [UIImage], duration: Double, isInfinite: Bool=false) {
imageView.stopAnimating()
imageView.animationImages = images
imageView.animationDuration = duration
if !isInfinite {
imageView.animationRepeatCount = 1
} else {
imageView.animationRepeatCount = 0
}
imageView.startAnimating()
}
So whenever I call this, it would stop any existing animation in place and animate it with new images.
And once the VPN has connected:
case NEVPNStatus.connected:
self.vpnButton.highlightedImage = UIImage(named: "OrangePressed")
self.animateImages(imageView: self.vpnButton, images: premiumImages, duration: 0.25)
self.vpnButton.image = UIImage(named: "OrangePremium-3")
Only the loadingImages get properly animated. The second set premiumImages doesn't animate and only shows the last frame.
I suspect that stopAnimating() takes some time to accomplish, and ideally, I needed a completion handler here to know when to kick off the imageView.startAnimating().
So here is where I am at now. I still haven't been able to get it to work and I've tried a lot of variations. Here is my original code for a single animation.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
var images = [UIImage]()
var images2 = [UIImage]()
images += [#imageLiteral(resourceName: "circle1"), #imageLiteral(resourceName: "circle2"), #imageLiteral(resourceName: "circle3"), #imageLiteral(resourceName: "circle4")]
images2 += [#imageLiteral(resourceName: "circle4"), #imageLiteral(resourceName: "circle3"), #imageLiteral(resourceName: "circle2"), #imageLiteral(resourceName: "circle1")]
imageView.animationImages = images
imageView.animationDuration = 4.0
imageView.animationRepeatCount = 2
imageView.startAnimating()
}
}
I am able to animate the first images array with the properties I've set for duration and count. However, I just do not understand how I would write this to add a second set of images to animate immediately after. I know I need to use this somehow:
UIView
.animate(withDuration: 4.0,
animations: {
//animation 1
},
completion: { _ in
UIView.animate(withDuration: 6.0,
animations: {
//animation 2
})
})
Can someone show me how I would write this given my current images arrays using the same imageView object to display both animations? I want my first animation (images) to have a duration of 4 seconds and my second animation (images2) to have a duration of 6 second immediately following the first animation. I can't figure out what I need inside the animations parameter.
i think the error is that you mix here 2 things:
UIView.animate -> animate controls and properties
UIImageView.startAnimating -> start a loop of images in an UIImageView
but they don't do the same they are very independent. but UIView animation is normally for an other use case. only one thing is that they maybe have the same duration like your UIImageView animation, but you don't set the duration of your UIImageView. maybe when you set the animation duration of your image view to the duration of UIView animation then it is done on the same time range.
myImageView.animationDuration = 2;
and for the second loop
myImageView.animationDuration = 4;
Other Solutions
the thing is you need to know when an image loop ist completed. but there is no event for this (i did not found any)
there are some solutions on StackOverflow for this:
1 performSelector afterDelay
Set a timer to fire after the duration is done. for this you need also to add an animation duration to your image view:
myImageView.animationDuration = 0.7;
solution from here: how to do imageView.startAnimating() with completion in swift?:
When the button is pressed you can call a function with a delay
self.performSelector("afterAnimation", withObject: nil, afterDelay: imageView1.animationDuration)
Then stop the animation and add the last image of imageArray to the imageView in the afterAnimation function
func afterAnimation() {
imageView1.stopAnimating()
imageView1.image = imageArray.last
}
2 Timer
this is similar to performSelector afterDelay but with NSTimer.
you find a description here UIImageView startAnimating: How do you get it to stop on the last image in the series? :
1) Set the animation images property and start the animation (as in
your code in the question)
2) Schedule an NSTimer to go off in 'animationDuration' seconds time
3) When the timer goes off, [...]
add to point 3: then start the next animation
3 CATransaction
solution from here: Cocoa animationImages finish detection (you need to convert it to swift 3 syntax but it can be a starting point
Very old question, but I needed a fix now, this works for me:
[CATransaction begin];
[CATransaction setCompletionBlock:^{
DLog(#"Animation did finish.");
}];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.window.bounds];
imageView.animationDuration = 0.3 * 4.0;
imageView.animationImages = #[[UIImage AHZImageNamed:#"Default2"],
[UIImage AHZImageNamed:#"Default3"],
[UIImage AHZImageNamed:#"Default4"],
[UIImage AHZImageNamed:#"Default5"]];
imageView.animationRepeatCount = 1;
[self.window addSubview:imageView];
[imageView startAnimating];
[CATransaction commit];
4 Offtopic: Manual do the Image Animation
thats a little offtopic, because here they do the image animation manually. for your use case you just change the logic which image from index is visible. count forward until last image, then backwards until first image. and then stop the loop. not nice solution but in this solution is added a image transition animation:
Solution from here: Adding Image Transition Animation in Swift
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
let images = [
UIImage(named: "brooklyn-bridge.jpg")!,
UIImage(named: "grand-central-terminal.jpg")!,
UIImage(named: "new-york-city.jpg"),
UIImage(named: "one-world-trade-center.jpg")!,
UIImage(named: "rain.jpg")!,
UIImage(named: "wall-street.jpg")!]
var index = 0
let animationDuration: NSTimeInterval = 0.25
let switchingInterval: NSTimeInterval = 3
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = images[index++]
animateImageView()
}
func animateImageView() {
CATransaction.begin()
CATransaction.setAnimationDuration(animationDuration)
CATransaction.setCompletionBlock {
let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(self.switchingInterval * NSTimeInterval(NSEC_PER_SEC)))
dispatch_after(delay, dispatch_get_main_queue()) {
self.animateImageView()
}
}
let transition = CATransition()
transition.type = kCATransitionFade
/*
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
*/
imageView.layer.addAnimation(transition, forKey: kCATransition)
imageView.image = images[index]
CATransaction.commit()
index = index < images.count - 1 ? index + 1 : 0
}
}
Implement it as a custom image view would be better.
I know you said that this didn't work for you, but if you just want to execute animations right after another, I believe this really is the best option.
You should be able to do something like this:
let imageView = UIImageView()
UIView.animate(withDuration: 0.5, animations: {
//animation 1
}, completion: { (value: Bool) in
UIView.animate(withDuration: 1.0, animations: {
//animation 2
})
})
This does one animation directly after another, which a longer duration. Of course you still need to define what the animations are, but I hope this helps.
I'm not sure if this is the best way to do this, but I've found a solution to my problem. Please give feedback if there is a better way. I was able to accomplish multiple animations in a single UIImageView consecutively by using: self.perform(#selector(ViewController.afterAnimation), with: nil, afterDelay: 4.0)
This calls the afterAnimation function:
func afterAnimation() {
imageView.stopAnimating()
imageView.animationImages = images2
imageView.animationDuration = 6.0
imageView.animationRepeatCount = 1
imageView.startAnimating()
}
I needed animations to each last a specific amount of time and to be able to chain many of them together. It solves my problem.
I have one view controller and I kept one full mage view in that view controller.And i have some image name like 1.png,2.png,3.png , like 6 images.What I need is I need to show as like slide .i.e for every 2 second one image should be in image view. I have done it in Objective-C. But I am beginner in Swift, so not able to do it. How to do this?
#implementation ViewController {
UIImageView* imgView; // your UIImageView
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[self navigationController] setNavigationBarHidden:YES animated:YES];
UIImage* img1 = [UIImage imageNamed:#"11.jpg"];
UIImage* img2 = [UIImage imageNamed:#"s2.jpg"];
imgView = [[UIImageView alloc] initWithFrame:self.view.frame]; // create a UIImageView with the same size as the view.
imgView.animationImages = #[img1, img2]; // use a nice NSArray literal to pass in your images.
imgView.animationDuration = 2.0*2.0; // 2 seconds for each image (x3 images)
[self.view addSubview:imgView]; // add UIImageView to view
[imgView startAnimating]; // start animating
}
Like that in Swift I need to do :
I am having image view name as imagview.And please don't compare the Obj-C code. Because there I have added some library file for animating. Can i code to do this continuous image showing for every 2 seconds in Swift?
var imagesListArray = [UIImage]()
for imageName in 1...3
{
imagesListArray.append(UIImage(named: "\(imageName).png")!)
}
// You can also use below code to add images if not want to use loop
// imagesListArray.append(UIImage(named: "1.png")!)
// imagesListArray.append(UIImage(named: "2.png")!)
// imagesListArray.append(UIImage(named: "3.png")!)
self.imageView.animationImages = imagesListArray
self.imageView.animationDuration = 2.0
self.imageView.startAnimating()
if let urlStringArr : NSArray = tempDic["get_image"] as? NSArray
{
if urlStringArr.count != 0
{
var imagesListArray = [UIImage]()
if urlStringArr.count > 1
{
for i in 0..<urlStringArr.count
{
let url = URL(string:urlStringArr[i] as! String)
if let data = try? Data(contentsOf: url!)
{
let image: UIImage = UIImage(data: data)!
imagesListArray.append(image)
}
}
cell.imagePet.animationImages = imagesListArray
cell.imagePet.animationDuration = 5.0
cell.imagePet.startAnimating()
}
else
{
if let getUrlString : String = urlStringArr[0] as? String
{
if getUrlString != ""
{
cell.imagePet.sd_setImage(with: URL(string:getUrlString), placeholderImage:nil)
}
}
}
}
}
I am using Xcode 11.3.1 and Swift 5.2.
Say you have an image array and UIImageView as follows:
var images = [UIImage]()
#IBOutlet weak var imageView: UIImageView!
Then you can set all images to UIImageView and start animating by following code:
imageView.animationImages = images
imageView.animationDuration = 2 * images.count
imageView.startAnimating()
The animationDuration is the amount of time it takes to go through one cycle of the images.
I have this asset as the background of a view and its assigned to the background using the code described below.
The animation is to get the diagonal rows animate, so they move from left to right when the loading is happening.
Any pointers of how to get this done?
var view = UIImageView()
view.translatesAutoresizingMaskIntoConstraints = false
view.image = UIImage(assetIdentifier: "background-view")
view.layer.cornerRadius = 8.0
view.layer.masksToBounds = true
view.contentMode = .ScaleAspectFill
view.clipsToBounds = true
view.backgroundColor = UIColor.whiteColor()
return view
"background-view" is here
I guess the best would be to have all the images needed ( all the frames ) to create the animated image you want and then put these images in UIImageView's animationImages property.
For instance, if you get a loading bar gif loading_bar.gif, you can get all the different images in that gif ( c.f. this tutorial among others : http://www.macobserver.com/tmo/article/preview-extracting-frames-from-animated-gifs ).
Load all the images in your code ( in the assets folder for instance ) and then do something like :
func getAnimatedImages -> Array<UIImage>
{
var animatedImages = Array<UIImage>()
var allImagesLoaded = false
var i = 0
while !allImagesLoaded
{
if let image = UIImage(named: "background_" + String(i))
{
animatedImages.append(image)
i++
}
else
{
allImagesLoaded = true
}
}
return animatedImages
}
( if you called your images background_0, background_1, etc... )
and then
self.yourBackgroundImageView.animationImages = self.getAnimatedImages
self.yourBackgroundImageView.startAnimating()
I would use the method class func animatedImageNamed(_ name: String, duration duration: NSTimeInterval) -> UIImage?
From the Apple doc:
this method would attempt to load images from files with the names ‘image0’, ‘image1’ and so on all the way up to ‘image1024’. All images included in the animated image should share the same size and scale.
If you create an animated image you can assign it to your UIImageView and it will animate automatically.
As for the image creation #Randy had a pretty good idea :)
my label and toolbar disappear from the view when i run the app hidden behind my image
this is my viewdidload code
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var tiger1 = Tigers()
tiger1.name = "BengalTiger"
tiger1.age = 1
tiger1.breed = "Bengal"
tiger1.fact = "live in the bengal area"
tiger1.image = UIImage(named: "BengalTiger.jpg")!
self.nameLabel.text = tiger1.name
self.ageLabel.text = String(tiger1.age)
self.breedLabel.text = tiger1.breed
self.factLabel.text = tiger1.fact
self.imageView.image = tiger1.image
tigersArray.append(tiger1)
}
and this is my struct:
struct Tigers {
var image = UIImage(named: "")
var name = ""
var age = 0
var breed = ""
var fact = ""
}
Natives metods
insertSubview:(UIView *) aboveSubview:(UIView *)
or
insertSubview:(UIView *) belowSubview:(UIView *)
You can use:
self.view.sendSubviewToBack(imageView)
and that will put it behind your other views
Here you see the imageView in the back of the other view elements, so the button and label will be shown on top of the image view:
Below you see the elements are behind the image view so they will be covered up by the image.
You can arrange elements in the document outline by dragging them up and down.