I notice that, if I perform add/ expand animation within an UIScrollView
, it will cause unwanted scrolling behavior, when the UIScrollView
fill with enough content to become scroll-able.
As you can see in the following animation, initially, the add/ expand animation works just fine.
When we have added enough item till the UIScrollView
scrollable, whenever a new item is added, and UIScrollView
will first perform scroll down, and then scroll up again!
My expectation is that, the UIScrollView
should remain static, when add/ expand animation is performed.
Here’s the code which performs add/ expand animation.
Add/ expand animation
@IBAction func add(_ sender: Any) {
let customView = CustomView.instanceFromNib()
customView.hide()
stackView.addArrangedSubview(customView)
// Clear off horizontal swipe in animation caused by addArrangedSubview
stackView.superview?.layoutIfNeeded()
customView.show()
// Perform expand animation.
UIView.animate(withDuration: 1) {
self.stackView.superview?.layoutIfNeeded()
}
}
Here’s the constraint setup of the UIScrollView
& added custom view item
Constraint setup
Custom view
class CustomView: UIView {
private var zeroHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var borderView: UIView!
@IBOutlet weak var stackView: UIStackView!
override func awakeFromNib() {
super.awakeFromNib()
borderView.layer.cornerRadius = stackView.frame.height / 2
borderView.layer.masksToBounds = true
borderView.layer.borderWidth = 1
zeroHeightConstraint = self.safeAreaLayoutGuide.heightAnchor.constraint(equalToConstant: 0)
zeroHeightConstraint.isActive = false
}
func hide() {
zeroHeightConstraint.isActive = true
}
func show() {
zeroHeightConstraint.isActive = false
}
}
Here’s the complete source code
https://github.com/yccheok/add-expand-animation-in-scroll-view
Do you have any idea why such problem occur, and we can fix such? Thanks.
2
Answers
I did a little research on this and the consensus was to update the
isHidden
andalpha
properties when inserting a view with animations.In CustomView:
In your view controller:
Also, the constraints in your storyboard aren’t totally correct. You are seeing a red constraint error because autolayout doesn’t know the height of your stackView. You can give it a fake height and make sure that "Remove at build time" is checked.
Also, get rid of your scrollView contentView height constraint defined as
View.height >= Frame Layout Guide.height
. Autolayout doesn’t need to know the height, it just needs to know how subviews inside of the contentView stack up to define its vertical content size.Everything else looks pretty good.
Because of the way stack views arrange their subviews, animation can be problematic.
One approach that you may find works better is to embed the stack view in a "container" view.
That way, you can use the
.isHidden
property when adding an arranged subview, and allow the animation to update the "container" view:The "add view" function now becomes (I added a Bool so we can skip the animation on the initial add in
viewDidLoad()
):And we can get rid of all of the
hide() / show()
andzeroHeightConstraint
in the custom view class:Since it’s a bit difficult to clearly show everything here, I forked your project with the changes: https://github.com/DonMag/add-expand-animation-in-scroll-view
Edit
Another "quirk" of animating a stack view shows up when adding the first arranged subview (also, when removing the last one).
One way to get around that is to add an empty view as the first subview.
So, for this example, in
viewDidLoad()
before adding an instance ofCustomView
:This will make the first arranged subview a zero-height view (so it won’t be visible).
Then, if you’re implementing removing custom views, just make sure you don’t remove that first, empty view.
If your stack view has
.spacing = 0
noting else is needed.If your stack view has a non-zero spacing, add another line: