UICollectionView cell disappears when i animate(with my custom animation) scrollToItem function - ios

I just trying to make a custom animation when i scroll to item programmatically. So when I do not compose my animation and using default by cell do not vanishing, but when i put scrolltoItem func inside UIView.animate func the last cell first vanishing and then scrollToItem animates.
In the second picture in the uppermost collectionView the located before indie game cell firstly disappears and only then collectionView scrolls from indie game cell to the next
Why this behavior takes place? Why when i do not animating it purposefully in my way, and just calling scrollToItem with animated = true func, nothing eliminates? if someone do know what happens with the cells, please give me a clue.
UIView.animate(withDuration: 10, delay: 0, options: .curveEaseInOut, animations: {
self.appsCollectionView.scrollToItem(at: IndexPath(item: self.actualNumberOfTheCell, section: 0), at: .centeredHorizontally, animated: false)
}, completion: nil)

I think you should have to do it with self.view.layoutIfNeeded()
self.appsCollectionView.scrollToItem(at: IndexPath(item: self.actualNumberOfTheCell, section: 0), at: .centeredHorizontally, animated: false)
UIView.animate(withDuration: 10, delay: 0, options: .curveEaseInOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
Hope it will work

Your reused cells might be overlapping because of the sudden scroll. The latest cell might have not been dequeued properly and is perhaps initialized using a content of a previous cell -> which is most likely an empty cell that hasn't been properly displayed during the scroll.
Try to reset your cell content using:
prepareForReuse() inside your cell's controller.
You should reset your UI to a default state here.
Here's the docs link to it
Don't forget to call a UI display/setup method for your cell, which should display your UI elements.
Hope it helps!

I think the issue is caused by collectionView recycling the cell too early, as you are using scrollToItem with animation = false.
I tried to split the animation to several smaller steps, It works, but the scroll is not smooth. Here is the code:
// self is extended from UICollectionView
scrollTo(x: 100, duration: 0.6, count: 4) { (finished) in
}
private func scrollTo(x:CGFloat, duration:TimeInterval, count:Int, completion:#escaping (Bool)->Void)
{
let xOffset = (x - contentOffset.x)/CGFloat(count)
let durationPart = duration/TimeInterval(count)
scrollToPart(xOffset: xOffset, duration: durationPart, count: count, completion: completion)
}
private func scrollToPart(xOffset:CGFloat, duration:TimeInterval, count:Int, completion:#escaping (Bool)->Void)
{
UIView.animate(withDuration: duration, animations: {
self.contentOffset.x += xOffset
}) { (finished) in
if count <= 1
{
completion(finished)
}
else
{
self.scrollToPart(xOffset: xOffset, duration: duration, count: count-1, completion: completion)
}
}
}
I used scrollToItem with animated = true at last.

Related

Slot machine animation using UITableView

I need to implement slot-machine animation according to provided design and timings.
It should perform infinite scroll, until some event will be triggered. After that animation, it should slow down and stop on defined position
For this task I have used next solution:
UITableView with fixed-height cell. It is the same cell with the only difference - icon or text (depends on indexPath.row)
Scroll is only down-to-up that's why I'm using last cell as start point in resetScrollPosition method
If first element reached, scroll position resets to start point
Animation performed as contentOffset change with linear option. In completion block, if animation is still needed, it's called again. If don't needed - slowing animation with easeOut option started
var isRolling: Bool = false
func startScroll() {
isRolling = true
UIView.animate(
withDuration: 0.05,
delay: 0,
options: .curveLinear,
animations: {
self.tableView.contentOffset.y -= self.rowHeight
},
completion: { _ in
if self.isRolling {
self.startScroll()
} else {
self.resetScrollPosition
UIView.animate(
withDuration: 0.7,
delay: 0,
options: .curveEaseOut,
animations: {
self.tableView.contentOffset.y -= 8 * self.rowHeight
},
completion: nil
)
}
})
}
private func resetScrollPosition() {
tableView.reloadData()
tableView.contentOffset.y = startOffset
tableView.reloadData()
}
func stopScroll() {
isRolling = false
}
The problems:
After calling resetScrollPosition, in animations completion block, tableviews contentOffset.y value is updated but tableView stays on the same position. I have tried to change direct contentOffset changing to setContentOffset, scrollToRow, scrollToRect, wrap it in main queue - no changes
Slowing animation should scroll 8 items. It's performed but first 6 items aren't visible during animation, only the last two.
Check the issue gif (jump 2 -> 11 is ok):
Replaced UITableView with UIScrollView
Uploaded code to gist - https://gist.github.com/OlesenkoViktor/76845c5448b421ead0a2303af2b1161d
Thanks #Paulw11 for his idea

Animate View Off-Screen To The Right and Back In From the Left

I'm trying to replicate an animation found on the Apple App Store seen here. The app icons move from left to right continuously like a carousel and I'm trying to produce the same behaviour for a single UIView. Is anyone able to help with this? Really struggling:
Something I tried but it stops and repeats the animation without continuing from left to right.
UIView.animateKeyframes(withDuration: 5, delay: 0, options: .repeat, animations: {
viewOfImageViews.center.x += container.bounds.width +
}, completion: nil)
Here is one way you can archive this effect:
Add a collection view
Set cell width the same width as your superview
Set your collection view scroll direction to horizontal
Now in the code when the collection is loaded you scroll to the first section
DispatchQueue.main.async {
self.collView.scrollToItem(at: IndexPath(item: 0, section: 1), at: .left, animated: true)
}
Now you can add this code below so when animation is done it updates the cells and scroll again
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
colors.append(colors.removeFirst())
collView.reloadData()
DispatchQueue.main.async {
self.collView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .left, animated: false)
self.collView.scrollToItem(at: IndexPath(item: 0, section: 1), at: .left, animated: true)
}
}
Change colors array to your array name which contains the images

Animation of UICollectionView height looks strange, cells zoom out

I'm trying to show a UICollectionView in a UITableViewCell. Initially the CollectionView shouldn't be shown, but when the users presses a button the CollectionView should become visible with an animation. I got this working however the first time the CollectionView becomes visible it looks like the cells get zoomed out, if I hide the CollectionView and expand it again, the animation looks correct:
http://g.recordit.co/DBhZCmJKPj.gif
This is the code for animation the change:
func expand() {
tableView?.beginUpdates()
UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveLinear, animations: {
self.imageViewDisclosureIndicator.setImage(UIImage(named: "arrow-up"), for: .normal)
self.collectionViewHeight.constant = self.collectionView.intrinsicContentSize.height
self.layoutIfNeeded()
self.isExpanded = true
}, completion: nil)
tableView?.endUpdates()
}
func collapse() {
tableView?.beginUpdates()
UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveLinear, animations: {
self.imageViewDisclosureIndicator.setImage(UIImage(named: "arrow-down"), for: .normal)
self.collectionViewHeight.constant = CGFloat(0.0)
self.layoutIfNeeded()
self.isExpanded = false
}, completion: nil)
tableView?.endUpdates()
}
Any help would be appreciated!
Try putting self.layoutIfNeeded outside the animation.
Based off your code, I don't see why you need that line of code, but it is probably the cause for your problem. I think that the content would even load fine without that line, because the size of the content view of the collection view is independent of the height of the collection view.

Cell Animation Stops when swipe left/right or pull table view out of screen

I can't figure out why animation of tableViewcell frizzes when tableView is pulled out out of screen or stoppes when you start to close menu.
To let you better understand the problem, here is a gif
I implement Tap Gesture Recognizer at custom UITableViewCell Class
let tap = UITapGestureRecognizer(target: self, action: "tapAction")
self.addGestureRecognizer(tap)
func tapAction() {
let animationWidth = leftMenuWidth * 0.27
UIView.animateWithDuration(0.75, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .AllowUserInteraction, animations: {
self.colorIndicator.frame.size.width += animationWidth
}) { (true) in
UIView.animateWithDuration(0.75, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .AllowUserInteraction, animations: {
self.colorIndicator.frame.size.width -= animationWidth
}, completion: { (true) in
print("Animation Complete")
})
}
Also i implement sliding menu by using this cocoaPods - https://github.com/jonkykong/SideMenu
Thanks.
The cells are likely being reloaded which is causing the animations to reset.
Try tracking the state of whether or not a cell has been tapped so that when it's reloaded you can show the animation as already complete. You can do this by with a simple dictionary.
At the top of your view controller, define:
private var tapped = [Int : Bool]()
Next, in cellForRowAtIndexPath: for your tableView check:
if let isSet = tapped[view.hashValue] where isSet == true {
// display animation complete. You probably don't want to re-animate
// it if it's scrolled back into view, so just get it to the completed state.
}
Finally, switch your tap action from using a gesture in the cell itself to didSelectRowAtIndexPath: inside your tableView:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// remember the cell has been tapped
tapped[view.hashValue] = true
// call your method to display the animation on the cell,
// something like cell.showAnimation(). It shouldn't animate if
// already displaying the completed animation state.
}
Also, I wouldn't recommend using += or -= operators when calculating the frame since calling it multiple times will keep growing or shrinking it. Use explicit values instead, like = animationWidth or = 0.

withRowAnimation effect disappears if user scrolls Swift

I'm facing a bugging issue concerning the insertRowsAtIndexPaths function and precisely it's withRowAnimation parameter.
With the help of the stack community i've been able to modify the effect of insertion from fast fade to a longer fade (by overriding the function), but the whole effect completely disappears if i scroll the table view upwards, hide the cells from the view and scroll back again.
Because the cells are being reused the effect is rendered totally useless.
I've tried using scrollToRowAtIndexPath function (doesn't work in this case - it initiates after the cells have already loaded, only then it scrolls down and the effect has already gone away) as well as setting the content offset to tableView.contentSize.height - the result is somewhat satisfactory, but again doesn't prevent vanishing of the insertion effect when the user scrolls.
Also willDisplayCell is not an option, because it animates the cell every single time the user scrolls and i need the animation to run just once. Urrgh)
So far i'm out of ideas of how to prevent this issue from happening.
UPDATE:
Added the suclass code
class CustomTable: UITableView{
override func insertRowsAtIndexPaths(indexPaths: [NSIndexPath], withRowAnimation animation: UITableViewRowAnimation) {
self.endUpdates()
self.beginUpdates()
for indexPath:AnyObject in indexPaths{
let cell:UITableViewCell? = (super.cellForRowAtIndexPath(indexPath as! NSIndexPath));
if cell != nil {
cell!.alpha = 0
let animationBlock = { () -> Void in
cell!.alpha = 1;
}
if UIView.respondsToSelector(Selector("animateWithDuration(duration: , delay: , usingSpringWithDamping dampingRatio: , initialSpringVelocity velocity: , options: , animations: , completion: ")){
UIView.animateWithDuration(3, delay: 3.0, usingSpringWithDamping: 1.5, initialSpringVelocity: 0.0, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: animationBlock, completion: nil)
}else{
UIView.animateWithDuration(3.3, delay: 5.0, options:UIViewAnimationOptions.TransitionCrossDissolve, animations: animationBlock, completion: nil)
}
}
}
}
}

Resources