I create a small UIView, and use animate method let it rotate forever:
let v2=UIView(frame: CGRect(x: 100, y: 100, width: 30, height: 30))
v2.backgroundColor=UIColor.orange
v2.transform=CGAffineTransform(rotationAngle: 0)
view.addSubview(v2)
UIView.animate(withDuration: 2, delay: 0, options: [.repeat,.curveLinear], animations: {
v2.transform=CGAffineTransform.init(rotationAngle: -CGFloat(Double.pi*2))
}, completion:nil)
But I found that the UIView did not rotate at all,why?
You are effectively saying "rotate to its current rotation" -- so nothing happens.
Try it like this - rotate to 180-degrees (.pi)... the repeat will then rotate another 180-degrees, and another, and another, etc:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let v2=UIView(frame: CGRect(x: 100, y: 100, width: 30, height: 30))
v2.backgroundColor=UIColor.orange
view.addSubview(v2)
UIView.animate(withDuration: 2, delay: 0, options: [.repeat,.curveLinear], animations: {
v2.transform = CGAffineTransform(rotationAngle: .pi)
}, completion:nil)
}
Edit - a little more clarification...
If you want a continuous rotation, you can use the above code. Note, though, that if you want a counter-clockwise rotation, you'll need to use a negative rotation angle of less-than 180-degrees.
For example:
UIView.animate(withDuration: 2, delay: 0, options: [.repeat,.curveLinear], animations: {
v2.transform = CGAffineTransform(rotationAngle: -.pi * 0.5)
}, completion:nil)
That will rotate it 90-degrees counter-clockwise, and then again, and again, and again, etc.
On the other hand, if you only want it to rotate once (to any arbitrary angle, clockwise or counter-clockwise), you'll want to use Core Animation as explained in this excellent article by #matt:
Taking Control of Rotation Animations in iOS
Rotated but full cycle 360 degrees
v2.transform=CGAffineTransform.init(rotationAngle: -CGFloat(Double.pi*2))
Change it to this
v2.transform=CGAffineTransform.init(rotationAngle: -CGFloat(Double.pi*2/3))
To verify that rotate happens
Related
I'm trying to create a Star Wars style scrolling text for a viewController.
I have the following code:
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 60.0, animations: {
let width = self.scrollingTextLabel.frame.width
let height = self.scrollingTextLabel.frame.height
self.scrollingTextLabel.frame = CGRect(x: 5, y: (180 - height), width: width, height: height)
}, completion:{ _ in
self.buttonTextLabel.text = "Play"
})
}
It works perfectly except for 1 thing, it speeds up, then slows down. This means, it's hard to read at the mid point. Is there a way to make the speed constant?
Pass in .curveLinear in the animation options to make the animation have a constant velocity:
UIView.animate(withDuration: 60.0, delay: 0.0, options: .curveLinear, animations: {
let width = self.scrollingTextLabel.frame.width
let height = self.scrollingTextLabel.frame.height
self.scrollingTextLabel.frame = CGRect(x: 5, y: (180 - height), width: width, height: height)
}, completion:{ _ in
self.buttonTextLabel.text = "Play"
})
I'm trying to make a cool launch screen but it's a little bit hard. I would like to make my image appear the way this appears:
what I would like
But for the moment the only animation I succeeded to do is this:
what I've made
The image I use is a PNG with transparent border and the yellow drawing.
The code I use to have the animation I have
( "yellowSide" is actually the name of the outlet from the imageView that hold my image with the yellow drawing):
func animation() {
yellowSide.frame = CGRect(x: yellowSide.frame.origin.x, y: yellowSide.frame.origin.y, width: 0, height: 47)
yellowSide.alpha = 0
UIView.animate(withDuration: 0.5, delay: 2.0, options: .curveEaseIn, animations: {
var yellowSideFrame = self.yellowSide.frame
self.yellowSide.frame = CGRect(x: yellowSideFrame.origin.x, y: yellowSideFrame.origin.y, width: 243, height: 47)
self.yellowSide.alpha = 1
}, completion: nil)
}
As you guess the width / value I enter are the value that I need to have so the image looks the way I want when it's fully appeared.
You are changing the frame but you are not clipping out of frame image . you need to do like below .
// in ViewDidLoad method
yellowSide.clipsToBounds=true
func animation() {
yellowSide.frame = CGRect(x: yellowSide.frame.origin.x, y: yellowSide.frame.origin.y, width: 0, height: 47)
yellowSide.alpha = 0
UIView.animate(withDuration: 0.5, delay: 2.0, options: .curveEaseIn, animations: {
var yellowSideFrame = self.yellowSide.frame
self.yellowSide.frame = CGRect(x: yellowSideFrame.origin.x, y: yellowSideFrame.origin.y, width: 243, height: 47)
self.yellowSide.alpha = 1
}, completion: nil)
}
I'm trying to create an animation where an object moves from one keypoint to the next smoothly. As of right now the object does move to the different key points but instead of transitioning to each one as soon as it finishes one animation it automatically jumps to the next keypoint but with no transition animation in between. This is the function I'm using:
func keyframeAnimate () {
UIView.animateKeyframes(withDuration: 3, delay: 0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0, animations: {
let translation = CGAffineTransform(translationX: 150, y: 150)
self.square.alpha = 0.5
self.square.transform = translation.rotated(by: CGFloat.pi).scaledBy(x: 2, y: 2)
})
UIView.addKeyframe(withRelativeStartTime: 1.01, relativeDuration: 1.0, animations: {
let translation = CGAffineTransform(translationX: 100, y: 400)
self.square.alpha = 1
self.square.transform = translation.rotated(by: -CGFloat.pi).scaledBy(x: 1, y: 1)
})
})
}
Any help is appreciated!
Your problem is in the relative start and relative duration. As the documentation explains, these parameters should be values between 0 and 1 because these are fractions of the entire animateKeyframes(withDuration: duration
Currently there is a view I'm trying to translate(move), rotate and scale a view at the same time. For so strange reason it's only scaling it when I put scale at the bottom. But when I change the order and put the scaling first it rotates and translates the view properly but the scale of the view changes briefly to its correct scale before changing back to its original size. I need it to stay in it's scaled form. Here is the code:
class ViewController: UIViewController {
let newView = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(newView)
UIView.animate(withDuration: 1.0, animations: {
self.newView.transform = CGAffineTransform(translationX: 50, y: 70)//translation
self.newView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)//rotation
self.newView.transform = CGAffineTransform(scaleX: 1, y: 0.5)//scale
})
}
}
Try combine the transforms first, then apply them at a time:
let translate = CGAffineTransform(translationX: 50, y: 70)
UIView.animate(withDuration: 1.0, animations: {
self.view.transform = translate.rotated(by: -CGFloat.pi / 2).scaledBy(x: 1, y: 0.5)
})
Is there a way to animate an object in swift (UIView, UIButton, etc.) so that it slides out on the left side of the screen and slides in at the same time on the right side of the screen, that the parts of f.e. an UIView that already slided out on the left side are already sliding in again from the right side.
I hope you can understand my question, its a bit tricky to explain this problem.
I'm using Xcode + Swift 3.0.
Thank you.
that the parts of f.e. an UIView that already slided out on the left side are already sliding in again from the right side
This almost slipped by me. The only way you have one "view" appear in two places on a screen is by really having two views, one on the left and one on the right.
Then, you could set the widthAnchors (properly), hide the subviews (properly), and animate. If the animation is fast enough (my one-sided slide out is set for 0.3 seconds) the user would think it's all one view.
You can use UIView.animate(). Trigger a second animation after the first has completed.
Possible implementation to get the idea:
var container = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0))
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 50.0, height: 50.0))
view.center = CGPoint(x: 100, y: 100)
view.backgroundColor = UIColor.green
container.addSubview(view)
let screenWidth = CGFloat(356.0)
// animate to left
UIView.animate(withDuration: 2.0, delay: 0.0, options: [], animations: {
view.center = CGPoint(x: -view.frame.size.width, y: view.frame.origin.y)
}, completion: { (finished: Bool) in
//set view to right of screen
view.center = CGPoint(x: view.frame.size.width + screenWidth, y: view.frame.origin.y)
// animate back to center
UIView.animate(withDuration: 2.0, delay: 0.0, options: [], animations: {
view.center = CGPoint(x: 100, y: 100)
})
})