How I can sync animations in Table View with Swift - swift

I have a table view with animation in each cell, the animation is a circle blinking but when made scroll the new row blink in different time. The idea is all circles blink at same time.
Thanks by any help. I had 2 days try different things. The last is make my own animation with a timer and save the time in global variable. But i think that core animation should have something for do that.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myClassCell", for: indexPath) as! MyClassCell
cell.circleBlinking.alpha = 0
View.animate(withDuration: 1, delay: 0, options: [.repeat, .allowUserInteraction, .curveLinear], animations: {
cell.circleBlinking.alpha = 1} )
}
return cell
}

Finally i found a solution for the requirement. I made the animation with a timer.
I created a global timer that change a global variable each 1/24 secs from 0 to 1 and from 1 to 0
When pass by cellForRowAt I create other timer just for that cell but the function is just give the value alpha from my global variable that is doing modified by the main timer. So that way I have all circles sync
If somebody know how do that with animate welcome with your answer.
Already I uploaded the code to Github with solution.
https://github.com/wilmanro77/TableViewWithAnimationInCells

Related

Checking If every row in table view have image hidden or not

Is there any way to check inside a function : func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) If rest of the rows ( instead of the first one ) have image hidden or not.
If images of rows which are greater then indexPath.row - 0 are all hidden or not.
So basically I would like to get the first row ( image ) of the table view hidden when the rest one are hidden as well. The simple check boxes.
This how I'm hiding them :
let row = indexPath.row
if row > 0 {
UIView.animate(withDuration: 0.5, animations: {
let currentCell = self.engineStatusTableView.cellForRow(at: indexPath) as! DropDownViewCell
if !currentCell.checkMark.isHidden {
currentCell.checkMark.isHidden = true
} else {
currentCell.checkMark.isHidden = false
}
})
}
Thanks in advance!
It's generally not a good idea to keep your state inside of cells. Cells are reused and somewhat expensive to create, so you want to let UITableView control the creation and manage their reuse.
But, hopefully, your datasource knows if the checkmark is supposed to be hidden or not and you can ask it without having to create a cell to do that.

Cell loaded in cellForItemAt, but not in visibleCells

I have a custom UICollectionView and the cells are loaded in cellForItemAt but when I try to get all the visible cells by using visibleCells I'm not getting all the cells.
For example, in cellForItemAt, I'm setting the alpha of the labels in the cells to 0. When panned, I want the alpha of those labels change to 1:
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
handleLabel(scrollView, active: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if pickerIsActive { handleLabel(scrollView, active: false) }
}
private func handleLabel(_ scrollView: UIScrollView, active: Bool) {
guard let pickerView = scrollView as? UICollectionView else { return }
let cells = pickerView.visibleCells.flatMap { $0 as? CustomCell }
panningIsActive = active
UIView.animate(duration: 0.3) {
cells.forEach { $0.label.alpha = $0.isSelected || active ? 1 : 0 }
}
}
And cellForItemAt:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCell
cell.label.alpha = 0
return cell
}
What can I do to change all the "loaded" cells instead of just the "visible" cells?
The visibleCells are only the on screen cells. This used to be everything initialized in cellForItem:at: but as of iOS 10 UICollectionView now prefetches to improve scrolling performance (see WWD 2016 video) which maybe why you are having this problem. Anyways it sounds like all you want to do is animate the cells to fade in when they come on screen. You can either move your animation logic to willDisplayCell or subclass UICollectionViewCell. UIColectionViewCell inherits from UIView, so you can override didMoveToSuperView in your UICollectionViewCell and call your animation method there, which will cause the cell to animate as it appears.
I am using Xcode 11.4 and Swift 5, and I had the exactly the same issue: .visibleCells is not giving me all the loaded cells.
By reading #Josh Homann's answer and the comments below, I figured out 2 solutions.
The first solution is same as the solution you reached at: customize cell appearance in collectionView(_:willDisplay:_:) after it's loaded but before it's displayed on the screen.
Another quick and dirty solution is to simply uncheck UICollectionView's 'Prefetch' option in attributes inspector.
This fixes the issue because by disabling prefetching, UICollectionView will stop pre-loading cells that are not displayed on the screen, so .visibleCells are now all the loaded cells. This solution will work fine if you're simply loading static or small local data in the cells. If you're prefetching large data (e.g. images) from network for upcoming cells, you probably need Prefetching Enabled, then solution 1 is your go-to option.
It sounds like you might want to try using layoutAttributesForElements(in:).
You'll need to implement your own collection view layout subclass (rather than using the delegate methods) but I think it will be worth it in the long term.
Rather than manually managing the animations (via UIView.animateWithDuration) you use this method to tell the collection view what properties cells should have at different positions, and as people pan the collection view, the correct properties are automatically applied.
I tried to find a good Swift reference for this, but I could't, but here's a post in Objective-C that you can follow if you want to try this approach:
https://bradbambara.wordpress.com/2014/05/24/getting-started-with-custom-uicollectionview-layouts/

Independently auto fade UITableView rows starting with the bottom row

Examples of row deletion usually implement textFieldDidEndEditing or some other gesture / user input method.
My version of an auto-deletion feature is to use animateWithDuration with alpha. It's simple and looks good.
The challenge is I would like to do this automatically via NSTimer or animateWithDuration independently of any user scrolling and user input. Just a simple fade-out starting with the newest bottom row and have it stay alpha 0 as it moves up the table.
Currently you don't see any rows when you open the app because the rows have already faded out. This is good. The problem occurs every time a user sends a new posts all the "invisible" rows appear again starting at alpha 1 and then all fade out together.
I need the previous rows above to stay at alpha 0 with only the new bottom row having alpha 1 then it fades away to alpha 0.
Is it because I need to use cellForRowAtIndexPathinstead? Or do I need to use the dequeueReusableCellWithIdentifier method?
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! CHEFTALKRecipeViewCell
let recipe = recipes[indexPath.item]
if recipe.posterId == posterId {
cell.textView!.textColor = UIColor.blackColor()
// STEP 1
cell.contentView.alpha = 1
} else {
// do something
}
return cell
}
// STEP 2
override func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
UIView.animateWithDuration(2.0) {
cell.contentView.alpha = 0
}
}
As much as I understand your problem is that all cells animate. Even the ones at the top.
If so, you can retrieve -visibleCells from UICollectionView and start animation if only their position is at the bottom of the screen.

Multiple animations are messed up

In collection view I have cells with image for every cell.
When the delegates of the collection being called, I set a different animation for every cell image according to data.
Every new cell that being added, I remove all other cells and reload the data of the collection.
What happens is that after I add a few cells, say cell 1 has stretch animation and cell 3 has scale animation, then cell 1 get stretch+scale .
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! FlowViewCell
cell.image.image=UIImage(named: moduleImage as String)
animate(moduleAnimation, image: cell.image)
....
func animate (kind:NSString, image:UIImageView)
// here I check what animation to apply (different between cells)
// *** can be
CABasicAnimation(keyPath: "transform.rotation")
//**** or
UIView.animateWithDuration(2.0, delay: 0.0, options: [.Repeat, .CurveEaseOut, .Autoreverse], animations: {
image.transform = CGAffineTransformMakeScale(0.15, 1.0)
Is there anything I can do to clear stuff? I think the reusable cells has something to do with it.
EDIT:
Have tried : cell.image.image=nil , no success .
Fixed it with this :
let index = data.count-1
let indexPath = NSIndexPath(forItem: index, inSection: 0)
collectionView.insertItemsAtIndexPaths([indexPath])
One should not use the reloadData function because there is no guarantee it will use the same cells again, and its not that good for performance, so instead update the cell that relevant.

Multiple touch when scrolling in TableView (change speed or direction)

I'm in the latest step of my TableView and I have a very simple problem: I would like to scroll (for example) direction to top and when I touch again the table (direction to bottom) it change the direction of the scroll.
At the moment, the problem is when I scroll to the bottom I can't scroll to top until the animation is finished.
Question:
How can I enable multi touch in my table view in order to change the direction of the scroll while the animation isn't finished?
Thanks in advance,
Regards.
All you need to do to stop an animation in progress is the following:
table.layer.removeAllAnimations()
Then you can start the new animation! Easy as pie!
If someone is having the same problem, the solution is modify the animateWithDuration in the willDisplayCell:
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
// Define the initial state (Before the animation)
cell.alpha = 0.25
// Define the final state (After the animation)
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.AllowUserInteraction, animations: { cell.alpha = 1 }, completion: nil)
}
The problem was the animation in my table cell.
Regards.