I have a tableview that has expandable cells. When you click on a cell a date picker shows inline. When you click on another, a different kind of picker shows. I have set it up so when you click on any cell, any open cells will close, so as to ensure that only one cell is open at a time.
My problem is: the animations for a) the first cell closing, and b) the second cell opening are overlapping, which doesn't look great at all.
When I click a cell I would like the expanded cell to close, and THEN the second cell to expand, with enough of a delay so the animations don't overlap.
I have looked for a Swift solution online but haven't been able to find an answer. I am fairly new to iOS dev, so don't know much about UIAnimation, etc.
Using Xcode 7.2, Swift.
Any help would be appreciated.
You can try to use the completion for that.
UIView.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: {
//your first animation
}, completion: {(finished:Bool) in
//your seconde animation (or whatever you want to be done when the first one is completed)
})
OR
You can use a CATransaction, see : Wait for Swift animation to complete before executing code
OR
You can try to force them to run on the same thread instead of using parallel threads ?
For example, here is how you can force an action to be done on the main thread :
dispatch_async(dispatch_get_main_queue()) {
//your animation
}
There may also be some other solutions,
good luck
Related
I cannot, for the life of me, figure out why my view won't animate, so I figured maybe it's because of some weird reason that I don't know about. Does anyone have any ideas on less common ways why UIView.animate() would fail to animate properly? The method I am using to animate my view is:
func animateView() {
print("1")
UIView.animate(withDuration: 5.0, delay: 2.0, options: [], animations: {
self.viewToAnimate.alpha = 0.0
print("2")
}, completion: {_ in
print("3")
})
}
What's even stranger (in my opinion), is that when I run, the console outputs
1
2
3
immediately, and does not take into consideration the delay of 2.0 seconds or the duration of 5.0 seconds... It appears my "animation" is instantaneous, making my view disappear immediately with an alpha of 0.
Any thoughts?
Here are the reasons that I can think of:
1- You can check your device settings General-> Accessibility-> Vision-> Reduce Motion
2- You can check if anywhere in the code you call UIView.setAnimationsEnabled(false) https://developer.apple.com/documentation/uikit/uiview/1622420-setanimationsenabled
3- Try to call layoutIfNeeded on the view before calling the animation on the view. This has to do with how animations work, it needs initial state and end state and then it projects the difference between both states on a time graph. https://www.objc.io/issues/12-animations/animations-explained/
4- You are not calling the method on the main thread which can make it ask weird. Try to call it in a dispatch_main block
I have an issue on my swift iOS app and i'm not able to understand which is the real problem. I have a UITabBarController with five UINavigationControllers on each tab. Main content of these controllers are UICollectionView filled dynamically from a WebService with custom UICollectionViewCells (about 30 for each CollectionView) with custom UIImageViews, custom UILabels and custom UIButtons loaded from custom xib files.
When i push few controllers all is working good (CollectionViews become a bit slower but i think it's normal for memory usage) but when a NavigationController contains 6 or 7 controllers and i try to scroll down, my UI is freezed, the app doesn't crash and i don't receive any kind of runtime error. I can still exit using Home button but the app is completely locked.
I'm dequeuing every cell in every collectionView with identifier and i'm using this attributes in every custom cell for performance:
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen().scale
What i tried
Debug views too see if some UIWindow or UIView is covering the controller view
Stop image loading and show blank imageViews
Clear code used in UICollectionView scroll delegate methods
But the issue is always reproducible on 6th or 7th controller, making some stress test. I gave a look to FPS too, but values are always from 40 to 60 that seems good. CPU usage is always very high, 90/100 % but method didReceiveMemoryWarning is never fired.
My goal would be that my app could push many controllers without freezing or become very very slow, but i can't understand what i'm missing.
Thanks to Philip Mills
Issue is that i was calling this code in my custom UICollectionViewCell setup:
func rotateWithDuration(duration: NSTimeInterval, indeterminate: Bool) {
UIView.animateWithDuration(duration, delay: 0.0, options: .CurveLinear, animations: {
self.transform = CGAffineTransformRotate(self.transform, CGFloat(M_PI))
}, completion: { finished -> Void in
if indeterminate {
self.rotateWithDuration(duration, indeterminate: indeterminate)
}
})
}
View rotation animation was running indefinitely in every cell, so the CPU was a bit sweat.
for button in buttonGroup {
UIView.animateWithDuration(1, animations: {
button.alpha = 0
})
}
VS
UIView.animateWithDuration(1, animations: {
for button in buttonGroup {
button.alpha = 0
}
})
I have more than 40 buttons in buttonGroup,could be more later, I wonder which way is better?
The standard is resource consumption.
You can test the performance of a block of code in xcodes unit test class and measure the speed of each. Create a Unit test framework and the method you need will be there in the template.
Are all your buttons in the same superview? If so consider embedding them in their own UIView and simply adjusting the alpha on that single view instead of all your UIButtons.
Obviously Second one. Because in case of first the UIView.animateWithDuration is called many (total button in buttonGroup) times. This is not efficient programming and also animation become choppy. But in case of second one UIView.animateWithDuration called only one time and accomplished the same result.
You don't have to write some Unit tests. just take a look at xCode debug navigator (shortcut: cmd + 6), look at app's CPU and memory, compare it. Or maybe you can use instruments to compare it. Personally i prefer the second one. (agree with #Md.Muzahidul Islam)
Problem
scrolling to the bottom of table view is slow
the table view contains about 25 items
and there is a bit of complexity in creating each cell
so creating 25 of them at the same time takes about 200 ms(believe me there is no way I can make it any more optimized)
Soloutions I've tried
there are basically two options for scrolling to bottom of table view(And I have searched the entire stack over flow for this)
tableView.scrollRectToVisible OR tableView.setContentOffset
tableView.scrollToRowAtIndexPath
the problem with the first option is, although it is pretty fast and it doesn't recreate every cell in the way from top to bottom of tableView, I need to call a new main queue to get it to work. if I call it in the same queue as the one that called tableView.reloadData(), then there will be a strange lag when scrolling the tableview(logs show that lots of cells are being re created unnecessarily, and I mean lots of them). and let me add that both threads are main thread. but still I must call the dispatch_get_main_queue() to get rid of that awkward lag. however new main thread adds a good delay to the initial load.
here is my code:
func loadData(groupID: String){
self._chats = self._cache[groupID]!
_tableView.reloadData()
dispatch_async(dispatch_get_main_queue()) {
let rect = CGRect(x: 0, y: self._tableView.contentSize.height - self._tableView.bounds.height, width: self._tableView.contentSize.width, height: self._tableView.bounds.height)
self._tableView.scrollRectToVisible(rect, animated: false)
}
}
again if I don't use the dispatch_get_main_queue() the tableView would be supper laggy. and if I do use it, then there will be about 100 ms delay in execution which makes the initial loading slow.
the second option is slow too, cause scrolling to the last indexPath means creating every cell in the way. and that cannot happen in the background and doing it in the main thread means freezing the UI for about 200 ms.
can you suggest any other solution or find something wrong with what I'm doing? I've tried every thing and still tableView isn't fast enough.
You can use Time Profiler one of Xcode Instruments to understand on which of your processes your app stack.
I'm trying to implement transition used in settings menu in Facebook's Paper app: http://blog.brianlovin.com/design-details-paper-by-facebook/#1. I'm using my custom UIViewControllerAnimatedTransitioning object, but I can't achieve the same effect, no matter what type of animation I'm using. So I have some questions:
1) Which animation is used? It looks like cells start to move really fast, and then halt to their final position. Looks like I need POPDecayAnimation, but the result isn't even close.
2) Is delay between animations achieved with setting animation's beginTime depending on cell's index? Or first cells have bigger velocity than last cells?
As Injectios suggested AMWaveTransition is kinda close to Paper's animation. I ended up using it with some adjustments.
I also asked this question on pop github page, you can view it here. Their answer might be useful if you want to implement this animation yourself:
Hey! I implemented that in Paper. The animations on each cell are POPSpringAnimations, and they're connected together by (every frame) updating the toValue of each animation to point to the current value of the one before. Hope that helps!
In cellForRowAtIndexPath, use UIViewAnimation block.
Set cell properties as per your requirement:
indentationLevel
indentationWidth
shouldIndentWhileEditing
Then in animation block, change frame position.
For example for first cell, indetationLevel = 1, and indentationWidth = cell.frame.size.width, then update it to indetationLevel = 0 and indentationWidth = 0 in that animation block. And for the further cells you can multiply this values by (cellIndexPath+1)
For more details visit : https://developer.apple.com/library/ios/Documentation/UIKit/Reference/UITableViewCell_Class/index.htm
P.S.: Update the logic as per your requirement