How to animate a UIImage constraints in Swift 4 - ios

I am making a card app and I need to make an animation so that a card would change its constraints to move to another place. How would I do this for a UIImage.

Hook the leading , trailing , CenterX OR CenterY constraint of the UIImageView and do this
self.imageLeadCon.constant = // value
UIView.animate(withDuration: 3.0 , animations: {
self.view.layoutIfNeeded()
// animation
}, completion: { _ in
// completion
})

I think you're confusing UIImage with UIImageView. The first one is the image's data representation, the second one is the View that displays the UIImage.
So I guess you want to move around the UIImageView. To do that obtain a reference to the constraints (e.g. by ctrl-dragging from the constraint in the storyboard to your UIViewController instance).
After that you can update the constraint in an animation block like here:
// Make sure the view is laid out as Mischanya Schtrigel stated
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.5) { // duration in seconds
myConstraint.constant = 50 // update your constraint here
self.view.layoutIfNeeded()
}
Contrary to the other answers, I like putting the constraint changes in the animation closure to make it more clear what is going to be animated.

First of all you have to drag and drop your constraint into your view controller, to make an outlet. The same way you are doing it with UIImageView or UITableView, etc.
Actually, for those who have watched WWDC (2014 I guess), Apple have explained how to animate UI in the proper way.
Firstly, you have to call layoutIfNeeded() method to make sure that everything on your view have laid out. After you can change your constraint and right after that in your animation block you call layoutIfNeeded() method to layout your constraint with the new value.
So code should look like that:
view.layoutIfNeeded() // to make sure your view have laid out
self.constraint.constant = //change your constant to any value
UIView.animate(withDuration: 1.0) {
self.view.layoutIfNeeded() //layout your constraint with the new value
}

Related

Swift - Animate only specific constraints

I'm trying to animate constraints in my ViewController.
In order to do that, I added this line to my code:
I'm just trying to change the height of a UIView() (from 0 to 100)
barHeight.constant = CGFloat(100)
UIView.animate(withDuration: 2) {self.view.layoutIfNeeded()}
The problem is that, with that line, all of the constraints are animated, and it's not what I would like.
Do you know how I could animate only specific constraints and not others?
Call layoutSubviews before you edit the constraint you want to animate. This will cause any pending layout updates to be applied without any animation and then you can change the next constraint with animation.
Like so:
self.view.layoutSubviews()
barHeight.constant = CGFloat(100)
UIView.animate(withDuration: 2) {self.view.layoutIfNeeded()}

Autoresizing UIView with UILabel inside, smoothly

I have a UIView, that contains a UILabel (and nothing else) inside it. I wish to expand and contract the view, making it look as though the label is expanding and contracting (via a button tap). I'm using a NSLayoutConstraint on the height of the view:
func labelExpansion() {
if (isExpanded) {
myViewConstraint.constant = shortLabelHeight
} else {
myViewConstraint.constant = longLabelHeight
}
UIView.animate(withDuration: 2.2, animations: {
self.view.layoutIfNeeded()
})
}
The problem is, the text in the label looks like it 'jumps'. As the label is resizing, the position of the text changes, until the animation is finished, when the label correctly redraws to the top of the view.
I have also tried removing the surrounding view, and adjusting the height constraint of the label alone; that was similarly jumpy.
How can I stop this jump during the animation, and fix the top of the label to the top of the view?
After trying a few things, I found an easy solution: set the Content Mode of the UILabel to 'Top'.
myLabel.contentMode = .top

Constraints not updating automatically in ios

I have created a storyboard as in the image. In that I have set the vertical spacing between the red view and tableView is around 20. Its working good.
But when i tried to change the height of red view then the tableview should comes up with the constraints I added but the table view is remained constant at the same place.
I used the following code
redView.frame.size = CGSize(width: 1008, height: 0)
self.view.layoutIfNeeded()
Whenever you are adding a constraint to any object on storyboard then onwards that object's frame will be maintained by autolayout engine. This is the primary design principle I guess. In this case what you can simply do is that just make an outlet of the desired constraint which you want to update and update that constraint within your code. For your understanding I am attaching a screenshot.
Now after making a constraint outlet it must look like as follows.
#IBOutlet weak var containerViewHeight: NSLayoutConstraint!
Now to update the height you just have to do one thing.
containerViewHeight.constant = 0
In my opinion if this update is not working inside viewDidLoad or viewWillAppear then please update inside viewDidLayoutSubviews because when viewDidLoad get called then iOS doesn't apply the layout properly.
In my case what I will do is -
override func viewDidLayoutSubviews() { //This ensures all the layout has been applied properly.
super.viewDidLayoutSubviews()
containerViewHeight.constant = 0
}
Note: - To achieve some nice animation effect during layout changes you can apply this constraint update inside an UIView animation block like as follows. But remember, to see the effect nicely you have to call this after presenting the view properly like after viewDidAppear etc.
UIView.animateWithDuration(1.0, delay: 0.2, usingSpringWithDamping: 8.0, initialSpringVelocity: 1.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
containerViewHeight.constant = 0
self.view.layoutIfNeeded()
}, completion: nil)
Sorry for any mistake.
Update/Edit is most welcome.
Hope this helped. Thanks
You should be using Autolayout to manipulate the redView's height. Modifying its frame's size is not Autolayout. Modify its height constraint (if it exists)
You need to either use constraints or changes to frames! You cannot do both!
What you need to do is to make an outlet reference to your constraint and change its constant-value instead.
If you placed the code in viewdidload or viewwillappear, you will find issues like this. You need to put the code after all the constraints are loaded.
Also, make an object of the height constraint and name it for example redViewHeight.
and change its value by: redViewHeight.constant = 0
It will work!
Replace the constraints for the views with the following.
Redview
Top constraint to ParentView
Leading Constraint to ParentView
Trailing constraint to ParentView
Height Constraint
TableView
Top constraint to RedView
Leading Constraint to ParentView
Trailing constraint to ParentView
Bottom constraint to ParentView
Now wire an IBOutlet for the HeightConstraint of RedView and modify its constant value. The UITableView will adjust its height as desired.

Swift mimic animated: animation

I am using self.navigationController?.setNavigationBarHidden(true, animated: true)
I wonder where I can see how that animation is built in code?
I want to mimic its behavior with another custom UIView
The animation is just a slide up, so an animation is created that changes the y-origin of the view being animated.
If using auto layout, you should have a top constraint that specifies that the view's top y position is equal to the superview's top y position. You can reference these NSLayoutConstraints using #IBOutlet like you can with other storyboard elements, so in your view controller:
class MyViewController {
#IBOutlet var viewToAnimate: UIView!
#IBOutlet var topConstraint: NSLayoutConstraint!
}
You will notice that NSLayoutConstraint has a constant property, which just specifies a value to add to the second constraint attribute when calculating the resulting layout frames using that constraint. So in the case of the topConstraint, you want to add -viewToAnimate.bounds.height*, so that the bottom of the view sits just out of sight at the top of the superview.
You animate changes using the UIView class method animateWithDuration(_:animations:) - any animatable UIView properties that are changed inside the animation closure will be animated over the specified duration. But when you change your constraint's constant property, the view properties aren't changed until another layout pass is performed on the view. You can invalidate the layout, and let the layout happen in the next pass implicitly with view.setNeedsLayout(), but we need the layout pass to happen inside the view's animation block for the animation to work. So instead, you can use layoutIfNeeded() to force the subviews to layout immediately.
Put together, your animate method might look something like this:
class MyViewController {
// ...
func animateViewUp() {
UIView.animateWithDuration(0.3) {
self.topConstraint.constant = -self.viewToAnimate.bounds.height
self.view.layoutIfNeeded()
}
}
}
In reality, you would likely specify a method that allows you to toggle between a shown/hidden state, but the above code should get you started.
*N.B. Check which way around the constraint is specified! If the constraint is specified in terms of your superview, then a negative constant will move the subview downwards!
Short answer: You can't. The source for Apple's frameworks is not provided. However, most of their animations are built on top of the same Core Animation framework that us third party developers use.
What is the effect this creates? I'm not sure I've ever animated away the navigation bar on a view controller that's in place. Can you post a GIF of the animation? I can probably give you an idea of how it's done if I know what it looks like.

Animate subview on UIViewController view

I have UITableView as a subview over UIView (parent view) of UIViewController. When i'm animating my parent view as below:
UIView.animateWithDuration(duration, animations: {
viewController?.view.frame = CGRectMake(0,0,320,568)
}, completion: {_ in
})
I observed that my subview (table view) is not animating. I tried setting Autoresizing Mask of subviews to flexibleWidth and flexibleHeight, but din't get any success. Anybody having any idea why its happening.
If you are using auto layout (which is the default in iOS 8/9 on Xcode 6/7) you need to change the constraints of your view inside he UIView animation closure, instead of changing the frame.
If you are not using auto layout, then you can update the frame as above, however, I'd imagine you are. Thus you need to call layoutSubviews, then programatically set new constraints that represent your desired change to the layout, and finally call layoutSubviews again, inside the animation closure.
Example:
func AnimateBackgroundHeight() {
self.view.layoutSubviews()
UIView.animateWithDuration(0.5, animations: {
self.heightCon.constant = 600 // heightCon is the IBOutlet to the constraint
self.view.layoutSubviews()
})
}

Resources