I have a uitableview cell and it will animate when the cell is displayed. These cells are in tableviews and these tableviews are tabs of a uitabbarcontroller. But if a user presses one of the four tabs for the first time then the cells will animate, but if a user clicks a new tab and goes back to the previous tab the cells will not animate. How can I make it so that the cells animate everytime the tableview is presented. Here is my code, can someone please show me how i can make the cell animate each time the view is presented and not only when the cell is presented.
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let rotationTransform = CATransform3DScale(CATransform3DIdentity, 10, 10, 0)
cell.layer.transform = rotationTransform
UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.1, options: .curveEaseOut, animations: {
cell.layer.transform = CATransform3DIdentity
}, completion: nil)
}
Reload the data on view will appear controller method:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableview.reloadData()
}
Also, you may need to reset to the starting state before you animate again. why? because when you scroll your table view the cells that appears will not animate. they will have the final state after animation (reusable cells).
Another thing that you may scoll and the top cell will disappear before completing the animation. I am not sure what would happen. maybe it will not take its final state. and when you get back to it or that cell get reused that cell will not have the final state. but, if you reset to the first state before you start animating again that will solve all the problems.
reset animation:
cell.layer.transform = nil
// you may need to layout the cell. not sure. after this.
// then the rest of your code that animates the cell.
Related
No action is performed on UITableViewCell when blinking animation is implemented, it starts blinking that is fine but not clickable or swipable. I have tried some solutions but unable to fix it. Code is below.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.backgroundColor = UIColor.colorWithHexString(hexStr: "#FDFAEB")
cell.blink()
return cell
}
Animation extension code:
extension UIView {
func blink() {
self.alpha = 0.5;
UIView.animate(withDuration: 0.7, //Time duration you want,
delay: 0.0,
options: [.curveEaseInOut, .autoreverse, .repeat],
animations: { [weak self] in self?.alpha = 1.0 },
completion: { [weak self] _ in self?.alpha = 0.8 })
}
}
Please tell me, what is the reason, and how can I fix this?
By default user interaction is disabled during animations. you need to add the .allowUserInteraction option to your set of options.
(And note that if you're animating a view's position the user won't be able to tap on the view as it moves. Behind the scenes, a view jumps to it's destination position as soon as the animation begins. It only appears to move across the screen. If you want to handle tapping on a view as it moves across the screen it's a lot more complicated.)
I'm adding simple stack animation to my tableViewCell which animates like cells are being add to a stack. When I tap the UIButton that segues me to the tableView I first see a static cell which has my values and then after a small gap my animation works. I don't know why my tableView shows that cell before animation ? Here is my code for the VC :
override func viewDidAppear(_ animated: Bool) {
animateTable()
}
func animateTable() {
let cells = tableView.visibleCells
let tableHeight: CGFloat = tableView.bounds.size.height
for i in cells {
let cell: UITableViewCell = i as UITableViewCell
cell.transform = CGAffineTransform(translationX: 0, y: tableHeight)
}
var index = 0
for a in cells {
let cell: UITableViewCell = a as UITableViewCell
UIView.animate(withDuration: 1, delay: 0.05 * Double(index), usingSpringWithDamping: 0.9, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
cell.transform = CGAffineTransform(translationX: 0, y: 0);
}, completion: nil)
index += 1
}
}
When your view appears, it would have the UITableView data already populated via a call to reloadData. You do the animation only after the view appears. So at that point, you'll see the existing data for a fraction of a second and then the animation would kick in.
If you don't want the data to appear at all before the animation runs, you might want to not show data as soon as the view loads by doing something like the following - this might not be the best solution, but it is the easiest to implement:
1: Add a new variable to indicate whether you've run the animation or not.
var wasAnimated = false
2: Check this variable in numberOfRowsInSection and return 0 if the animation has not run yet.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if !wasAnimated {
return 0
}
// Rest of the original code
}
3: Set the flag at the beginning of animateTable and then reloadData before you execute the rest of the animation code.
func animateTable() {
wasAnimated = true
tableView.reloadData()
// The rest of the original code
}
That should get you the behaviour you wanted :)
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.
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)
}
}
}
}
}
I haven't been able to find any examples of this online. How can I achieve the following effect? Instead of the standard slide-to-left effect when tapping a table row, I'd like the view controller transition animation to look like the following:
User taps a cell in the table
The cell starts growing to fill the screen, pushing other rows above and below it "offscreen".
As the cell grows, cells elements (text, images, etc.) cross-fade into the new view's contents until the new view completely fills the screen.
I'd like to also be able to interactively transition back into the table view by dragging up from the bottom edge, such that the reverse of the above is achieved. i.e. view starts shrinking back into a normal table view cell as the "offscreen" cells animate back into position.
I've thought about taking a snapshot of the table and splitting it up at the points above and below the cell, and animating these snapshots offscreen as part of a custom view controller transition. Is there a better way? Ideally I'd like to not take snapshots, as I may want to have animations, etc., still happening in the table view rows as they fade offscreen.
First thing first, i have seen your post today and his is written in swift programming language.
the follwing code is to expand the selected cell to the full screen, where the subviews will fade out and background image will expands.
First complete cellForRowAtIndexPath, then in didSelectRowAtIndexPath,
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
isSelected = true
selectedCellIndex = indexPath.row
tableView.beginUpdates()
var cellSelected: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cellSelected.frame = tableCities.rectForRowAtIndexPath(indexPath)
println("cell frame: \(cellSelected) and center: \(cellSelected.center)")
let newCell = cellSelected.frame.origin.y - tableOffset
println("new cell origin: \(newCell)")
var tempFrame: CGRect = cellSelected.frame
variableHeight = cellSelected.frame.origin.y - tableOffset
tempFrame.size.height = self.view.frame.height
println("contentoffset: \(tableView.contentOffset)")
let offset = tableView.contentOffset.y
println("cell tag: \(cellSelected.contentView.tag)")
let viewCell: UIView? = cellSelected.contentView.viewWithTag(cellSelected.contentView.tag)
println("label: \(viewCell)")
viewCell!.alpha = 1
UIView.animateWithDuration(5.0, delay: 0.1, options: UIViewAnimationOptions.BeginFromCurrentState, animations: {
tableView.setContentOffset(CGPointMake(0, offset + self.variableHeight), animated: false)
tableView.contentInset = UIEdgeInsetsMake(0, 0, self.variableHeight, 0)
tableView.endUpdates()
cellSelected.frame = tempFrame
viewCell!.alpha = 0
println("contentoffset: \(tableView.contentOffset)")
}, completion: nil)
}
then update your heightForRowAtIndexPath, as
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if isSelected && (selectedCellIndex == indexPath.row) {
return self.view.frame.height
}else {
return 100
}
}
Ignore this if already solved. and this might be helpful to others.