Xcode Swift - Animating UIImageView Repetitively - ios

just quick inquiry in regards to implementing an issue I'm having with animating a UIImageView. I successfully implemented animating an image to slide off screen; but i want it to reappear when it exists the view to simulate a side-scroller game animation.
Something like this:
I've tried implementing a completion handler but struggled understanding the logic of how to implement it, so I removed my attempts; so my code is left as follows:
let oldCenter = background.center
let newCenter = CGPoint(x: oldCenter.x - 400, y: oldCenter.y)
UIView.animate(withDuration: 2, delay: 0, options: .curveLinear, animations: {
self.background.center = newCenter
}) { (success: Bool) in
print("Done moving image")
}
An example or pointers on how to achieved my desired animation would be appreciated!

let oldCenter = view.center
let newCenter = CGPoint(x: oldCenter.x - 400, y: oldCenter.y)
UIView.animate(withDuration: 2.0, delay: 0.0, options:
[.curveLinear, .repeat], animations: {
view.center = newCenter
}, completion: nil)

If you want to repeat the animation,
there is no need to implement the completion.
animate(withDuration:delay:options:animations:completion:) has options parameter (UIViewAnimationOptions), which is:
A mask of options indicating how you want to perform the animations.
For a list of valid constants, see UIViewAnimationOptions.
One of the constants for the UIViewAnimationOptions is repeat:
Repeat the animation indefinitely.
So, what you should do:
UIView.animateKeyframes(withDuration: 2.0, delay: 0.0, options: [.curveLinear, .repeat], animations: {
self.background.center = newCenter
}, completion: nil)
Again, implementing completion is not required for repeating the animation, implementing it is up to your case.

You can try UIView UIView repeat option
let oldCenter = background.center
let newCenter = CGPoint(x: oldCenter.x - 400, y: oldCenter.y)
UIView.animate(withDuration: 2, delay: 0, options: [.curveLinear, repeat], animations: {
self.background.center = newCenter
}) { (success: Bool) in
print("Done moving image")
if(success)
{
self.background.center = oldCenter
}
}

Related

Swift - animating UIImageView image

just a quick issue I'm having regarding animating a moving background image for my current application setup. Essentially I want to have my currently still background image scroll from left to right endlessly across my view; but I'm struggling piecing it all together. From a variety of various other sources I've comprised this function that isn't currently working, and i really can't figure out how or why.
func animate(_ image: UIImageView) {
UIView.animate(withDuration: 5, delay: 0, options: .curveLinear, animations: {
image.transform = CGAffineTransform(translationX: -100, y: 0)
}) { (success: Bool) in
image.transform = CGAffineTransform.identity
self.animate(image)
}
}
Any help/assistance is immensely appreciated!
You don't need to use CAffineTranform inside animateWithDuration, you can simply define the new center like:
let oldCenter = image.center
let newCenter = CGPoint(x: oldCenter.x - 100, y: oldCenter.y)
UIView.animate(withDuration: 1, delay: 0, options: .curveLinear, animations: {
image.center = newCenter
}) { (success: Bool) in
print("Done moving image")
}
Hope it helps.

UIView animate - Rotate and scale up, then rotate and scale down

I have a subclassed imageview that I'd like to fade in, scale up, and rotate, then continue rotating while scaling back down and fading out.
I am using a UIView animate block with a completion handler to handle the shrinking back down.
The problem is it's not a fluid animation. Before the completion handler runs, the animation stops before running again. I need it to be one nice "swoop" of an animation.
Code below:
let duration: TimeInterval = 3.0
let rotate = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
UIView.animate(withDuration: duration * 3, delay: 0, options: [.curveLinear], animations: {
// initial transform
self.alpha = 0
self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
// initial spin for duration of animaton
UIView.animate(withDuration: duration * 3, delay: 0.0, options: [.curveLinear], animations: {
self.transform = rotate
}, completion: nil)
// scaling and fading
UIView.animate(withDuration: duration, delay: 0, options: [.curveLinear], animations: {
UIView.setAnimationRepeatCount(3)
self.transform = self.transform.scaledBy(x: 0.8, y: 0.8)
self.alpha = 1
}) { (true) in
UIView.animate(withDuration: duration, animations: {
UIView.setAnimationRepeatCount(3)
self.transform = self.transform.scaledBy(x: 0.1, y: 0.1)
self.alpha = 0
})
}
}, completion: nil)
How can I get the animation to rotate the entire time while fading in and scaling up before scaling back down and fading out? The entire animation should last 3 seconds, and repeat 3 times. Thanks.
For your modified request I am expanding what you already saw using the block animations. As some have said, key frame animations may be better, regardless, here is the thought.
Create an animation that rotates the entire time by transforming the view.
Create another animation that does the scaling and fading based off the current transform (which is rotating). In this pass, I just created some variable to allow you to customize (and repeat) portions of the animation. I broke some things out to be clear and know I could refactor to write thing even more concise.
Here is the code
import UIKit
class OrangeView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
let duration: TimeInterval = 9.0
self.transform = CGAffineTransform.identity
// initial transform
self.alpha = 1
self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
// start rotation
rotate(duration: duration)
// scaling and fading
scaleUpAndDown(desiredRepetitions: 3, initalDuration: duration)
}
func rotate(duration: TimeInterval) {
UIView.animate(withDuration: duration/2.0,
delay: 0.0,
options: [.curveLinear], animations: {
let angle = Double.pi
self.transform = self.transform.rotated(by: CGFloat(angle))
}, completion: {[weak self] finished in
guard let strongSelf = self else {
return
}
if finished &&
strongSelf.transform != CGAffineTransform.identity {
strongSelf.rotate(duration: duration)
} else {
// rotation ending
}
})
}
func scaleUpAndDown(timesRepeated: Int = 0, desiredRepetitions: Int, initalDuration: TimeInterval) {
guard timesRepeated < desiredRepetitions,
desiredRepetitions > 0, initalDuration > 0 else {
self.transform = CGAffineTransform.identity
return
}
let repeatedCount = timesRepeated + 1
let scalingDuration = initalDuration/2.0/Double(desiredRepetitions)
UIView.animate(withDuration: scalingDuration,
delay: 0.0,
animations: {
let desiredOriginalScale: CGFloat = 0.8
let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale
self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
self.alpha = 1
}) { (true) in
UIView.animate(withDuration:scalingDuration,
delay: 0.0,
animations: {
let desiredOriginalScale: CGFloat = 0.1
let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale
self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
self.alpha = 0
}) { finshed in
self.scaleUpAndDown(timesRepeated: repeatedCount, desiredRepetitions: desiredRepetitions, initalDuration: initalDuration);
}
}
}
}
Finally here is another animated gif
I see the slight stutter in rotation at the start of the onCompletion.
I created a reduction with your code (shown below in the Blue View) and a variation in the Orange View. This was taken from the simulator and turned into an animated GIF, so speed is slowed down. The Orange View continues to spin as the complete transform just scales down.
This is the code for the layoutSubviews() for the Orange View
override func layoutSubviews() {
super.layoutSubviews()
let duration: TimeInterval = 3.0
let rotate = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
// initial transform
self.alpha = 0
self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
// initial spin for duration of animaton
UIView.animate(withDuration: duration,
delay: 0.0,
options: [.curveLinear],
animations: {
self.transform = rotate;
},
completion: nil)
// scaling and fading
UIView.animate(withDuration: duration/2.0, animations: {
self.transform = self.transform.scaledBy(x: 0.8, y: 0.8)
self.alpha = 1
}) { (true) in
UIView.animate(withDuration: duration/2.0, animations: {
self.transform = self.transform.scaledBy(x: 0.1, y: 0.1)
self.alpha = 0
})
}
}
Try using CGAffineTransformConcat()
CGAffineTransform scale = CGAffineTransformMakeScale(0.8, 0.8);
self.transform = CGAffineTransformConcat(CGAffineTransformRotate(self.transform, M_PI / 2), scale);

UITapGestureRecognizer Activate on Immediate Touch?

The title might be a little confusing, but is there a way I can Get this code to execute the moment I touch the uiview?
entry.transform = CGAffineTransform(scaleX: 0.975, y: 0.975)
speech.transform = CGAffineTransform(scaleX: 0.975, y: 0.975)
I have a UIView that I want to simulate a button press. Currently, the way I have it set up, It only triggers once my finger has left the screen
func voiceTap(sender: UITapGestureRecognizer? = nil) {
entry.transform = CGAffineTransform(scaleX: 0.975, y: 0.975)
speech.transform = CGAffineTransform(scaleX: 0.975, y: 0.975)
UIView.animate(withDuration: 0.2, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {
self.entry.transform = CGAffineTransform.identity
self.speech.transform = CGAffineTransform(scaleX: 0.975, y: 0.975)
}, completion: nil)
}
How to I get the code outside of the animation block to trigger the moment my finger touches the UIView?
You need to implement the methods (touchesBegan: withEvent: etc) to detect the received touch in your UIViewController and check if the touch corresponds to the UIView of your interest. And from there you can trigger an action.
Check this thread how to implement the methods
Or this one

Swift: Load .Xib with animation

Currently I am loading a new .Xib of class CreateAnAccount: UIView form a button pressed on another view.
At the moment it immediately switches to the Xib which is great, but is there a way of animating this? below is the code in the button.
#IBAction func createAnAccount(sender: AnyObject) {
let createAnAccountView = NSBundle.mainBundle().loadNibNamed("CreateAnAccount", owner: self, options: nil)[0] as! CreateAnAccount
createAnAccountView.frame = CGRectMake(0, 0, UIScreen.mainScreen().applicationFrame.size.width, UIScreen.mainScreen().applicationFrame.size.height + 20)
createAnAccountView.loginHandler = loginHandler
self.addSubview(createAnAccountView)
println("Create An Account Pressed")
}
Swift 4. Just place your animation code into layoutSubviews func. Works perfect for me.
override func layoutSubviews() {
super.layoutSubviews()
animate()
}
func animate() {
self.transform = CGAffineTransform(scaleX: 0.3, y: 2)
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: [.allowUserInteraction, .curveEaseOut], animations: {
self.transform = .identity
})
self.alpha = 1
}
Swift 5. #coldembrace answer
func animate() {
self.view.transform = CGAffineTransform(scaleX: 0.3, y: 2)
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: [.allowUserInteraction, .curveEaseOut], animations: {
self.view.transform = .identity
})
self.view.alpha = 1
}
You can try like this
UIView.transitionWithView(self.view, duration: 0.5, options:UIViewAnimationOptions.CurveEaseInOut,animations: {self.view.addSubview(createAnAccountView)}, completion: nil)
Moreover you change the UIViewAnimationOptions to have a desired effect.

Multiple UIView Animations

I have a UIButton that I have placed in the center of the screen using Interface Builder.
I want to animate the UIButton to move up and down and repeat the animation forever.
So far I have this in my didMoveToView:
UIView.animateWithDuration(3, animations: { () -> Void in
self.playBtn.transform = CGAffineTransformMakeTranslation(0, 10)
self.playBtn.transform = CGAffineTransformMakeTranslation(0, -10)
self.playBtn.transform = CGAffineTransformMakeTranslation(0, -10)
self.playBtn.transform = CGAffineTransformMakeTranslation(0, 10)
UIView.setAnimationRepeatCount(-1)
})
However it only runs the first line and moves the button down 10.
You can't change the transform to multiple things simultaneously. I would expect your code to cause no animation at all, as changing the transform more than once would cancel the animation.
Another problem with your code is that what you're saying is not how you ask for a repeating animation.
Still another problem is that you won't ever bring the button back to its starting place; the transforms are not additive.
What you need to do is chain animations together. This will be easiest if you drop down to Core Animation and make a grouped animation.
Or can do it with view animation by doing a keyframe animation, perhaps; this is not identical to what you want, but it will get you started:
Swift 2
let opts = UIViewKeyframeAnimationOptions.Repeat
UIView.animateKeyframesWithDuration(3, delay: 0, options: opts, animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.5, animations: {
self.playBtn.transform = CGAffineTransformMakeTranslation(0, 10)
})
UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.5, animations: {
self.playBtn.transform = CGAffineTransformIdentity
})
}, completion: nil)
Swift 3,4,5
let opts = UIView.KeyframeAnimationOptions.repeat
UIView.animateKeyframes(withDuration: 3, delay: 0, options: opts, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5, animations: {
self.playBtn.transform = CGAffineTransform(translationX: 0, y: 10)
})
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations: {
self.playBtn.transform = CGAffineTransform.identity
})
}, completion: nil)
But really, it would be better if you learned how animation actually works before you get into this kind of thing. From your code, it appears to me you are just thrashing.

Resources