I use UITableView with static cells.
If I use reloadData, than everything is OK.
If I try reloadRowsAtIndexPaths it hides row. Row appears if I drag tableView up-down(when cell is updated).
If your table cells are static (i.e., you are using the same cell object to replace the one that's currently displayed), what you're seeing is an artifact of the transition animation.
Think of it this way. Lets say you set UITableViewAnimationOptionFade. When the cell is to be replaced, the cell it's to be replaced with (which in this case is the exact same object) has a fade-in animation added to it. Then, the cell that is being replaced (again, it's all the same object) has a fade-out animation added to it. At the end, the cell is actually there, but it's invisible because the fade-out animation has made that cell object invisible.
In a non-static tableview, one in which the replacement cell is a different object than the cell to be replaced, this isn't a problem, as the animations are added to two different objects.
I had the same problem, it seems to be a bug. I experimented some and the problem doesn't occur when I set the animation option to UITableViewRowAnimationNone. Some other interesting stuff happens when you set that option to UITableViewRowAnimationTop, too.
I solved this by removing animation
tableView.reloadRows(at: [yourIndexPath], with: UITableView.RowAnimation.none)
Hope this helps to anyone searching for this.
Related
I'm relatively new to Swift and iOS and I have one issue - I have a custom SwipeCell class that extends UITableViewCell. It's a cell that can be swiped left and right, and has buttons on each side. For some reason if I made the buttons out of the frame of the cell when user swipes the cell they would appear but could not call an action, so my solution was to make cell wider than it is (so buttons can fit in it). Because it was done this way my cell has to have an offset by default for the total width of the buttons of the left (let's say 100), so it's position is X:-100.
And that's fine, and everything works fines with the cells, however there is one huge issue - if I call the deletion of any cell from the tableView like this
tableView.deleteRowsAtIndexPaths([tableView.indexPathForCell(activeCell)!], withRowAnimation: .None)
tableView then deletes the cell, and all of the other cells that are currently visible (doesn't happen with cells above or below the screen bounds) get moved to X:0 instead of staying at X:-100, so I assume that deleteRowsAtIndexPaths calls some function that resets the visible cells positions to 0,0. I'm currently setting swipe cells positions with layoutSubviews() since the number of buttons is dynamic and couldn't be determined upfront, but layoutSubviews is not the function where the bug happens.
So to sum up question - what function does deleteRowsAtIndexPaths call after deleting a cell that resets/redraws the visible cells?
deleteRowsAtIndexPaths deletes a row(s) from the tableView. This is handled internally by iOS. From Apple documentation:
Deletes the rows specified by an array of index paths, with an option
to animate the deletion.
Another interesting thing to note here is that this method does not modify your model (object that holds data used by your table view cells to render on themselves). You have to do that yourself. The cells are deleted, but if you call reloadData without deleting the row from your Model, cell will reappear.
Expect that cells get deleted and created all the time. Cells are very, very temporary objects. Write the code to create one when needed, and don't make any assumptions. Don't assume the cell is there later, don't assume it's in the same row, don't assume it displays the same data (because cells are recycled).
Since I could find out what happens inside of deleteRowAtIndexPaths, and why it changes frames of each Cell, I decided to just do my own function that deletes a row, by obtaining cells with tableView.visibleCells, and then just moving cells bellow the deleted cell up by a height of deleted cell. Thank you all for trying to help me, and especially thanks to Abhinav who told me that it was handled internally, which help me decide to write a custom code for the deletion.
I have an averagely sized table which is working perfectly, except for the row insertion animation (withRowAnimation). I've overriden it (with the help of stack community) to have a longer duration than the original system animation and it works just fine, but ...
Because i'm using custom cells as reusable cells - each time i scroll this effect is getting wiped out.
So the only solution i see is to stop the reuse.
I know this will interfere with the memory, but in this case its the only scenario left (of which i know).
My general question is how do i load a custom cell nib without using dequeueReusableCellWithIdentifier so that the reuse wouldn't happen.
Thank you.
You should use dequeueReusableCellWithIdentifier, not using it is a recipe for disaster.
Take a look into your code and when you dequeue a cell (reused or not, most of the time it'll be reused), the first thing you should do is set all elements in that cell back to the original state, so that that reused cell behaves like a non reused cell.
I don't know what you animation/implementation is about but here an example from a project I wrote with custom cells :
In each cell I added buttons, this could be 1, 2, 3,... buttons. If I did nothing in a reused cell I would have more buttons than expected because the old buttons would still be there...
So in my code the first thing I did after dequeing the cell would be to remove all the buttons.
let cell = tableView.dequeueReusableCellWithIdentifier("RelatedCell") as! RelatedCell
cell.removeAllActionButtons()
where my removeAllActionButtons (a method in my custom cell) method would be something like:
for button in actionButtons {
button.removeFromSuperview()
}
actionButtons is an Array containing all that buttons added to that custom cell
I have a UICollectionView I use like a tool selection container. You have many tools (the cells), when you select one, the former selected is deselected, and so on... You can only have one tool selected at a time.
The problem is that I can't manage to have the cells selected. When I tap the cell, the collectionView:didSelectItemAtIndexPath: is called. I then reload the selected cell to change it's appearance (I change the alpha of the image) by using the [collectionView reloadItemsAtIndexPaths:#[indexPath]].
Well that reloads the cell ok, except one damn thing: in the collectionView:cellForItemAtIndexPath: the cell never get the selected property set to YES! So I can never change the alphabecause I never know when I must draw a selected cell or not.
Worse: [collectionView indexPathsForSelectedItems] is always empty!!!
I don't even mention the collectionView:didDeselectItemAtIndexPath: that is never called...
Well, if someone can help me understand what is going on, thanks in advance...
When you call reloadItemsAtIndexPaths: the collection view discards those cells and creates new ones, therefor discarding the selected state of the cells.
I'd suggest a couple of different options:
1.) In collectionView:didSelectItemAtIndexPath: call cellForItemAtIndexPath: to get a reference to the selected cell and update it's appearance there.
2.) (My Favorite) Use a custom subclass of UICollectionViewCell if you're not already, and override the method setSelected:. There you'll be notified when the cell is selected and you can update the appearance from within the subclass.
With regards to selecting multiple cell at once, you should try the allowsMultipleSelection property [myCollectionView setAllowsMultipleSelection:YES] The docs for that are here: https://developer.apple.com/library/ios/documentation/uikit/reference/UICollectionView_class/Reference/Reference.html#//apple_ref/occ/instp/UICollectionView/allowsMultipleSelection
Otherwise, #daltonclaybrook's answer is sufficient.
I am a bit confused and don't have much else to turn to. I have an iOS application that gets messages from a server and populates it into a cell in a UITableView. Every time a certain object gets updated from the server that update triggers a cell animation. In our case we have a table of scores in a game. If someone loses a point their cell would flash red and if they gain a point their cell would flash green. Simple concept that works well and our users like the feedback. What they don't like is how when they scroll they see the cells have random colors associated with it and stay there for about a second. I believe that it has something to do with the way that the cells are being recycled. I tried various checks regarding this issue, checking that the cell has the same value, setting the color manually to white, etc. and non of these methods work.
All in all I am trying to only show the animation when the cell has been in view and not when the users is scrolling through the UITableView. Anyone have any advice or ideas?
Thanks
What is happening
Since table views reuse their cells you are ending up reused cells that is being flashed even though they shouldn't.
How to solve it
You can restore the reused cell to its default state either in preprareForReuse: on the custom table view cell or in the tableView:willDisplayCell:forRowAtIndexPath: delegate method (as ACB mentioned).
Since you are animating with UIView animations, you only need to change the value of the animated property to cancel the animation and return to the default state.
If you would have user Core Animation for the flash
If the animation was done using Core Animation you would instead have called removeAllAnimations on the animating layer. (For a flashing animation you probably wouldn't change the property on the layer, instead you would tell the animation to autoreverse. This would mean that removing the animation would change the color back to its original value.)
One option is to remove the animation and reset the color in willDisplayCell delegate method to the default color. If that doesn't work you can set the dequeueReusableCellWithIdentifier as follows,
NSString *aCellIdentifier = [NSString stringWithFormat:#"%d",indexPath.row];
UITableViewCell *aCell = [tableView dequeueReusableCellWithIdentifier:aCellIdentifier];
But this will be a problem if you have a lot data to display as it will create memory issues. Note that in this case you will not be reusing the table cells.
I have a drag&drop operation between 2 UITableViews. The cell could be reordered in the source TableView, or move to another TableView.
Because I need to move the cell between the two, I can't use the default reorder support. However, I want to make a similar animation like when the cell is moving around and the cell below them slide out.
Any hint in how do this animation?
UPDATE:
You can see what exactly I'm looking for in the pulse app.
You can always use deleteRowsAtIndexPaths:withRowAnimation: to remove it from the source and insertRowsAtIndexPaths:withRowAnimation: to insert it into the destination.
if you want to do something similar to what makes "Pulse" you have to use "UIScrollView" for each row that you have and within the Views you need, if you do it UITableView is more complicated and would not be so easy to move between them