Can all constraints in swift 3 be animated? - ios

I want to animate a view like using the following code:
UIView.animate(withDuration: 2.7, delay: 0.1, options: .allowAnimatedContent, animations: {
self.AVCenterY.constant = 0.8
}, completion: nil)
But it happens so fast it seems like it is not animated. On the other hand, when I animate the property alpha it is animated (it takes the 2.7 seconds to change). I used 2.7 sec to make sure the problem was that I was using a small duration time.

Constraints cannot be animated at all. It is the act of layout that can be animated:
UIView.animate(withDuration: 2.7, delay: 0.1, options: .allowAnimatedContent, animations: {
self.AVCenterY.constant = 0.8
theView.superview?.layoutIfNeeded() // *
}, completion: nil)
When we animate the act of layout (or when the runtime does so), then any constraint changes are also automatically animated.
Note that what I animate is the layout of the superview of the view that is to move. I called it theView but that is just something I made up. You will need an outlet to that view so that you can get its superview, and use the name of that outlet.

Related

How to stop UISegmentedControl segments animation

Is there any way to stop the animation of the method insertSegment(withTitle:at:animated)? Even if I set animated:false the segment animates, look this:
Please ignore the red ball.
The code that I am using to create the component is:
let segmentedControl = UISegmentedControl()
segmentedControl.sendActions(for: UIControlEvents.valueChanged)
segmentedControl.tintColor = UIColor.white
segmentedControl.selectedSegmentIndex = 0
view.addSubview(segmentedControl)
The constraint setup is ok, the frame width (100% - 16 pixels both sides) is the same all the time. The problem is related of the segments, not the parent view.
To add segments (this happens after a settings check):
segmentedControl.insertSegment(withTitle: "Bolinha 1", at: 0, animated: false)
Setting the frame doesn't work, since the problem is related to the inner views.
I tried to remove it using setAnimationsEnabled(false) but doesn't work.
Edit 1: Using segmentedControl.setWidth(segmentedControl.frame.width/3, forSegmentAt: 0) doesn't work.
Edit 2: Starting the view with UISegmentedControl(items: ["", "", ""]) does it replacing the whole component, this is a very heavy solution for this problem btw...
The project uses Swift 3.1.
Thank you.
I discovered that a animation has modifying the behaviour of the inner components.
Removing this animation fixed the problem:
view.setNeedsUpdateConstraints()
view.updateConstraintsIfNeeded()
UIView.animate(
withDuration: 0.5,
delay: 0.5,
usingSpringWithDamping: 1.0,
initialSpringVelocity: 2,
animations: { [weak self] in
self?.view.layoutIfNeeded()
}, completion: nil)
The correct solution for this is to avoid any animation during the build of constraints.

Flip view and increase view's size simultaneously (iOS)

I am successfully able to flip a view using the following code:
UIView.transition(from: firstView, to: secondView, duration: 1, options: UIViewAnimationOptions.transitionFlipFromRight, completion: nil)
However, I would like to increase this views height while the animation is occurring. Is this possible?
I tried animating the height before transitioning, but it does nothing:
//original height is 300.0
firstViewHeightConstraint.constant = 600.0
UIView.animate(withDuration: 0.3, animations: {
self.view!.layoutIfNeeded()
})
UIView.transition(from: firstView, to: secondView, duration: 1, options: UIViewAnimationOptions.transitionFlipFromRight, completion: nil)
You will need to call the other overload of UIView.transistion on the superview of the two views in question and manually animate out and in the views. For the new view you have to composite the flip rotation and the scale into a single matrix, set it as the initial transform and then animate to identity and for the old view do you do the inverse.

How to change the default layout animation curve in a custom UICollectionView layout engine?

I've got a collection view setup to run with a custom collection view layout. I can animate cells appearing and disappearing by changing their transformations and alpha on the UICollectionViewLayoutAttributes, however, I would like to change the animation curve to use springs + damping in order to make the cells "bounce" when they appear.
Does anybody have an idea of how I can achieve this?
Thanks,
Wrap your UICollectionView's deleteItems/insertItems/reloadItems calls inside UIView.animateWithDuration:delay:options:animations:completion: call.
Example:
let duration = 0.25 // Hardcoded keyboard animation duration and curve
let curve = UIViewAnimationOptions(rawValue: 7 << 16) // ↑
UIView.animate(withDuration: duration, delay: 0, options: curve, animations: ({ [weak self] in
self?.collectionView?.performBatchUpdates({
self?.collectionView?.deleteItems(at: deletedIPs)
self?.collectionView?.insertItems(at: insertedIPs)
self?.collectionView?.reloadItems(at: updatedIPs)
}, completion: nil)
}), completion: nil)

swift animateWithDuration animation not right

I am hiding my navigation bar and a UIView under it that acts as a extension bar to it when I scroll my page.
My app is built like:
VC that holds a container view with an embedded table view.
From the table view I have delegates that notify VC1 once a user scrolls up or down.
My problem now is that the animation dont looks that good. What I am trying to do is to animate the extension bar to animate up or down with a fade in or fade out effect as well. When that occurs I also update the top contraint on my container view so that the table view will fill the whole screen. (I am not sure if I use layoutneeded() right or if something else should be used when updating constraints)
My code:
func ContainerTableViewControllerScrolledUp(controller: ContainerTableViewController) {
self.navigationController?.setNavigationBarHidden(false, animated: true)
println("UP")
UIView.animateWithDuration(
1.5,
delay: 0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 0.5,
options: nil,
animations: {
self.extensionV.alpha = 1
self.tableVConst.constant = 0
}, completion: { finished in
self.view.layoutIfNeeded()
}
)
}
func ContainerTableViewControllerScrolledDown(controller:ContainerTableViewController) {
self.navigationController?.setNavigationBarHidden(true, animated: true)
println("DOWN")
UIView.animateWithDuration(
1.5,
delay: 0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 0.5,
options: nil,
animations: {
self.extensionV.frame.origin.y = CGFloat(-10)
self.tableVConst.constant = -41
self.extensionV.alpha = 0
}, completion: { finished in
self.view.layoutIfNeeded()
}
)
}
extensionV is the extension view
tableVConst is the top constraint for my container view that holds my table view
So how should I edit my code in order to get the extension view to animate up/down with a fade in/fade out effect?
Instead of calling self.view.layoutIfNeeded() in the completion block, try calling it inside the animation block on the last line before it returns.

Swift do I need layoutifneeded()

I am animating a view by:
#IBAction func showInfo(sender: AnyObject) {
UIView.animateWithDuration(1,
delay: 0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 0.5,
options: nil,
animations: {
self.infoContainer.frame.origin.y = CGFloat(30)
}, completion: nil
)
}
My question now is if I need to run layoutIfNeeded() afterwards?
You need to call layoutIfNeeded() when you change constraints. You don't need to call it when animating by origin
Since you are animating by setting a new frame, you don't need to call layoutIfNeeded().
My guess is that you asked this question because it's not working for you. If you setup the view with AutoLayout, and try to modify the frame directly, it won't work, you have to animate by modifying the constants in the constraints.

Resources