I am using 2 animations.
when the screen is launched, the first animation starts in viewDidLoad.
this animation is applied to 2 images called layer2 and layer3.
func firstAnimation(){
UIView.animate(withDuration: 1, delay: 0, options:
UIViewAnimationOptions.repeat , animations: {
self.layer2.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
self.layer3.transform = CGAffineTransform(scaleX: 2, y: 2)
}, completion: { finished in
})
}
when an image called layer0 is long pressed, then firstAnimation() is being stopped by this code:
layer2.layer.removeAllAnimations()
layer3.layer.removeAllAnimations()
and different animation is being applied to layer2 and layer3.
the second animation is
func secondAnimation() {
UIView.animate(withDuration: 20, delay: 0, options:
UIViewAnimationOptions.curveEaseOut , animations: {
self.layer2.transform = CGAffineTransform(scaleX: 10, y: 10)
self.layer3.transform = CGAffineTransform(scaleX: 10, y: 10)
}, completion: { finished in
})
}
when I want to delete the second animation and launch the first one again, the 2 images layer2 and layer3 are starting from the size that they gained because of the second animation. how to relaunch the first animation with the initial sizes of the images?
You can reset views that were transformed to their original scale by using CGAffineTransform.identity.
For example:
layer2.transform = .identity
Related
I was wondering how can i can recreate this animation? The first 2 cells stays as it is but only the cells from index 2 are having animation.
Right now i am recreating this by using
let rotationTransform = CATransform3DTranslate(CATransform3DIdentity, -500, 10, 0)
cell.layer.transform = rotationTransform
Some how this doesn't give a good look and feel like the one in the gif , is there any pod or some way to make this happen?
Additional INFO : The first cell is just a simple cell, the second cell is a collectionView and the next cells are repeating ones. The swipe is currently working with swipe gestures, i just need information on how recreate this zoom-in , zoom-out animation.
Any help would be appreciated.
Thanks
Edit : I tried changing the gif size to medium on the question and it wasn't playing so i changed it to normal size again.
I actually figured out a simple way to perform this animation. There might be better ways to do this, but just incase someone needs help in future.
We write 2 functions for zoomIn and zoomOut (can be used anywhere)
func zoomOut(view : UIView,duration : Double,delay : Double)
{
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
view.transform = CGAffineTransform.identity.scaledBy(x: 0.95, y: 0.95)
})
}
func zoomIn(view : UIView,duration : Double,delay : Double)
{
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
view.transform = CGAffineTransform.identity
})
}
Then we write functions for movement (Can be used anywhere)
func movementAnimation(duration:Double,X:CGFloat,Y:CGFloat,item:UIView)
{
UIView.animate(withDuration: duration) {
item.transform = CGAffineTransform(translationX: X, y: Y)
}
}
and finally we combine these 2 to get a similar animation !
zoomOut(view: Table, duration: 0.1, delay: 0)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
movementAnimation(duration: 0.2, X: -500, Y: 0, item: self.Table)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
movementAnimation(duration: 0, X: 500, Y: 0, item: self.Table)
movementAnimation(duration: 0.2, X: 0, Y: 0, item: self.Table)
}
zoomIn(view: self.Table, duration: 0.1, delay: 0.6)
Here first the view is zoomedOut (reduce scale to 0.95) then its moved outside scree with 0.2sec duration.Once its outside screen, its immediately moved to right side of the screen with 0sec duration. Then with a 0.2sec duration we move it back to original position. Now we call zoomIn to get the view back to its original size with a duration of 0.1sec. The 0.5sec is the total amount of time taken for the zoomOut + movementOut + movementIn functions.
And finally reloading the Table
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.Table.reloadData()
}
Hope this helps someone and thx to 'Nikunj Kumbhani' for the pod idea!
I'm having an issue trying to touch a label that keeps animating because during the animation it becomes an image (set the animation on repeat). Is there a way to touch it during animation (I cant't use UITapGestureRecognizer) ?
func animatePro() {
UIView.animate(withDuration: 2, delay: 0, options: [.autoreverse, .repeat], animations: {
//1.5 times it's normal size
self.proLabel.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}){ (finished) in
self.proLabel
.transform = CGAffineTransform.identity
}
}
func animateRev() {
UIView.animate(withDuration: 2, delay: 0, options: [.repeat], animations: {
//1.5 times it's normal size
self.revLabel.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}){ (finished) in
UIView.animate(withDuration: 2, delay: 0, animations: {
self.revLabel.transform = CGAffineTransform.identity
})
}
}
Add allowUserInteraction
options: [.allowUserInteraction,.autoreverse, .repeat]
I want to make an animation that move a background image from right to left than left to right.
I use this code but not works
UIView.animate(withDuration: 5, delay: 0, options: .repeat ,animations: { () -> Void in
imageView.transform = CGAffineTransform(translationX: -imageView.frame.width + self.view.bounds.width, y: 0)
UIView.animate(withDuration: 5, delay: 1, options: .repeat ,animations: { () -> Void in
imageView.transform = CGAffineTransform(translationX: +imageView.frame.width - self.view.bounds.width, y: 0)
})
})
I solved with this
UIView.animate(withDuration: 30.0, delay: 0, options: [.repeat, .autoreverse], animations: {
imageView.transform = CGAffineTransform(translationX: -imageView.frame.width + self.view.bounds.width, y: 0)
}, completion: nil)
Use the following code if you want to use the legacy animate(withDuration:animations:) API. However, you need to wait for the first animation to be finished - this means you have to use the completion block.
However, your value for translationX does not makes sense as well.
UIView.animate(withDuration: 1, animations: {
self.imageView.transform = CGAffineTransform(translationX: -self.imageView.frame.width, y: 0)
}) { _ in
UIView.animate(withDuration: 1) {
self.imageView.transform = CGAffineTransform.identity
}
}
I would strongly recommend having a look at the "new" way of doing Animations: UIViewPropertyAnimator(https://developer.apple.com/documentation/uikit/uiviewpropertyanimator)
Slide up animation will be triggered when a button is clicked.
func animation_onClick(action: String) {
let up = CGAffineTransform(translationX: 0, y: -30)
myView.transform = CGAffineTransform(translationX: 0, y: 0)
UIView.animate(withDuration: 0.5, delay: 0.0, options: [], animations: {
self.myView.transform = up
}, completion: nil)
}
My code means when the function runs, myView’s position will be set to (0, 0) referring to its original position every time before it was set to (0, -30).
But when I run the app, I repeatedly click the button, somehow myView doesn't go back to its origin, it goes below where it should be. What I mean is it's not supposed to go below its origin.
See the gif below.
Try the following
func animation_onClick(action: String) {
myView.layer.removeAllAnimations()
myView.transform = .identity
UIView.animate(withDuration: 0.5, delay: 0.0, options: [], animations: {
self.myView.transform = CGAffineTransform(translationX: 0, y: -30)
}, completion: nil)
}
I have a view controller that has a UIView that I call playerView. In playerView, I use an AVLayer and AVPlayerLayer to show the user a video. Image the Youtube app when you first click on any video.
How do I manipulate the frame of this playerView so that it can take up the entire screen. (Go full screen)
This is the current frame:
//16 x 9 is the aspect ratio of all HD videos
let height = view.frame.width * 9 / 16
let playerFrame = CGRect(x: 0, y: 0, width: view.frame.width, height: height)
playerView.frame = videoPlayerFrame
I was testing around in the YouTube app and their app only supports Portrait orientation (just like mine) due to how the animation of a video going full screen looks. How can I do this at the the tap of a button and even further when the user holds the device horizontally?
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.playerView.frame = ?
}, completion: nil)
Edit: Tried this but it doesn't really work how I want it... it doesn't take up the whole screen
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.playerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.height, height: self.view.frame.width)
self.playerView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
}, completion: nil)
I figured it out.
I create a global variable called isExpanded that will be set to true when we're in full screen mode. Also, I create a CGPoint variable called videoPlayerViewCenter so I can save the center before going full screen so I can set it again when going back to small screen.
This is the code that gets called when the user wants to go full screen
func fullScreenTapped(sender: vVideoPlayer) {
if !isExpanded {
//Expand the video
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.videoPlayerViewCenter = self.videoPlayerView.center
self.videoPlayerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.height, height: self.view.frame.width)
self.videoPlayerView.center = self.view.center
self.videoPlayerView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
self.videoPlayerView.layoutSubviews()
}, completion: nil)
} else {
//Shrink the video again
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
//16 x 9 is the aspect ratio of all HD videos
self.videoPlayerView.transform = CGAffineTransform.identity
self.videoPlayerView.center = self.videoPlayerViewCenter
let height = self.view.frame.width * 9 / 16
let videoPlayerFrame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: height)
self.videoPlayerView.frame = videoPlayerFrame
self.videoPlayerView.layoutSubviews()
}, completion: nil)
}
isExpanded = !isExpanded
}
To expand the video, I save the center in my global CGPoint variable and then set the frame. Then, I set the center and do a 90 degree turn using CGAffineTransform.
To shrink the video again, I basically set the settings to how they were before. (The order in which things are done is very important)
Another thing that's also very important is to override your layoutSubviews method in your videoPlayerView to be like this:
override func layoutSubviews() {
super.layoutSubviews()
self.playerLayer?.frame = self.bounds
}
This will make it so your playerLayer adjusts its frame as the view is getting bigger.
I know is too late but maybe someone else can find this code helpful.
I use to use Auto layout constraints in my views so animating must have a different approach.
func setMapFullScreen(_ fullscreen: Bool) {
if fullscreen {
// Set the full screen constraints
self.setFullScreenLayoutConstraints()
// Hide the navigation bar
self.navigationController?.setNavigationBarHidden(true, animated: true)
} else {
// Set small screen constraints
self.setSmallScreenLayoutConstraints()
// Show the navigation bar
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
// Animate to full screen
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}) { (finished) in
// ...
}
In my case a have I MKMapView and I want to tap on it in order to see the map fullscreen (and back).
This is the function that toogle the state.
As you can see, in the UIView.animate call, I animate only the self.view.layoutIfNeeded()
I also hide the navigation bar cause I have one ☺
Here my setSmallScreenLayoutConstraints and setFullScreenLayoutConstraints functions using SnapKit framework
func setSmallScreenLayoutConstraints() {
self.mapView.snp.remakeConstraints { (make) -> Void in
make.top.equalTo(self.mapLabel.snp.bottom).offset(8)
make.left.equalTo(self.view).offset(0)
make.right.equalTo(self.view).offset(0)
make.height.equalTo(150)
}
}
func setFullScreenLayoutConstraints() {
self.mapView.snp.remakeConstraints { (make) -> Void in
make.top.equalTo(self.view).offset(0)
make.left.equalTo(self.view).offset(0)
make.right.equalTo(self.view).offset(0)
make.bottom.equalTo(self.view).offset(0)
}
}
This is the result
Enjoy!!
As I said it is not an answer for your question. It is an idea and hope it helps you:
var rectangleView:UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Tap Gesture Recognizer for growing the rectangleView
let tapForward = UITapGestureRecognizer.init(target: self, action: #selector(self.tapForward(tap:)))
tapForward.numberOfTapsRequired = 1
// Configure the rectangleView
self.rectangleView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height))
self.rectangleView.transform = CGAffineTransform.init(scaleX: 0.65, y: 0.25)
self.rectangleView.backgroundColor = UIColor.red
self.rectangleView.addGestureRecognizer(tapForward)
self.view.addSubview(rectangleView)
}
And this going to be our tapForward(tap:) function:
func tapForward(tap:UITapGestureRecognizer) {
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: .curveEaseInOut, animations: {
self.rectangleView.transform = CGAffineTransform.identity
}) { (completed:Bool) in
// Completion block
}
}