drawViewHierarchyInRect:afterScreenUpdates: delays other animations
I used one of my Apple developer support tickets to ask Apple about my issue.
It turns out it is a confirmed bug (radar number 17851775). Their hypothesis for what is happening is below:
The method drawViewHierarchyInRect:afterScreenUpdates: performs its operations on the GPU as much as possible, and much of this work will probably happen outside of your app’s address space in another process. Passing YES as the afterScreenUpdates: parameter to drawViewHierarchyInRect:afterScreenUpdates: will cause a Core Animation to flush all of its buffers in your task and in the rendering task. As you may imagine, there’s a lot of other internal stuff that goes on in these cases too. Engineering theorizes that it may very well be a bug in this machinery related to the effect you are seeing.
In comparison, the method renderInContext: performs its operations inside of your app’s address space and does not use the GPU based process for performing the work. For the most part, this is a different code path and if it is working for you, then that is a suitable workaround. This route is not as efficient as it does not use the GPU based task. Also, it is not as accurate for screen captures as it may exclude blurs and other Core Animation features that are managed by the GPU task.
And they also provided a workaround. They suggested that instead of:
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
UIImage *im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Use im */
I should do this
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Use im */
Hopefully this is helpful for someone!
snapshotView of UIView render/draw in context with nothing
If you need a snapshot UIImage in the first place just use the method in your second code block. Create a UIView's category like
@implementation UIView (takeSnapshot)
- (UIImage *)takeASnapshot {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
@end
That's enough. You don't need snapshot a view and convert it to a image. In your case this process might cause the problem
Sharing an Image between two viewControllers during a transition animation
It's probably two different views and an animated snapshot view. In fact, this is exactly why snapshot views were invented.
That's how I do it in my app. Watch the movement of the red rectangle as the presented view slides up and down:
It looks like the red view is leaving the first view controller and entering the second view controller, but it's just an illusion. If you have a custom transition animation, you can add extra views during the transition. So I create a snapshot view that looks just like the first view, hide the real first view, and move the snapshot view — and then remove the snapshot view and show the real second view.
Same thing here (such a good trick that I use it in a lot of apps): it looks like the title has come loose from the first view controller table view cell and slid up to into the second view controller, but it's just a snapshot view:
Simultaneous animations block each other
Here's some useful code:
// We schedule a timer for a desired 30fps animation rate.
// In performAnimation: we determine exactly
// how much time has elapsed and animate accordingly.
timer = [[NSTimer scheduledTimerWithTimeInterval:(1.0/30.0) target:self selector:@selector(performAnimation:) userInfo:nil repeats:YES] retain];
// The next two lines make sure that animation will continue to occur
// while modal panels are displayed and while event tracking is taking
// place (for example, while a slider is being dragged).
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSModalPanelRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
NSTimer blocks other animations
This is a common symptom of having auto layout turned on but are probably trying to slide it across the screen by adjusting the frame
or center
. Auto layout is a iOS 6+ feature that controls the location and size of various UIView
elements. Unfortunately, when you have auto layout on, every time you change a label's value, it will reapply the constraints that dictate where the label should be positioned, defeating your attempts to animate it.
Two solutions:
Turn off auto layout by opening up your storyboard or NIB, click on the first "document inspector" tab on the rightmost panel, and then uncheck "Use Autolayout".
If you want to use autolayout, animate the moving of the control by changing constraints rather than changing
frame
orcenter
. See here for an example of how you can create anIBOutlet
for a constraint and then change that constraint programmatically in ananimateWithDuration
block.
References:
Cocoa Auto Layout Guide
Introduction to Auto Layout for iOS and OS X
Best Practices for Mastering Auto Layout
Auto Layout by Example
Layer animations removed when switching apps
When switching apps or view controllers, the system will let the animations on the layer stop (complete), so you can set removedOnCompletion
to NO
(the default is YES
), and it will work.
How to use performSelector: afterDelay: after doing animations?
From what I can gather, you're trying to perform a series of animations, each with a delay before they begin. So, instead of using performSelector:afterDelay:
to call the animations, you can nest calls to animateWithDuration:delay:options:animations:completion:
like this:
[UIView animateWithDuration:1.0f delay:2.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
//your first animations
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0f delay:2.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
//your second animations
} completion:^(BOOL finished) {
}];
}];
This method accepts an extra delay
parameter which sounds like what you're wanting. And since you're second animation is in the first's completion block, the animations will happen in sequence.
Related Topics
Disable Bitcode for Project and Cocoapods Dependencies with Xcode 7
How to Change the Color of an Uiimage
How to Disable Horizontal Scrolling of Uiscrollview
iOS Is It a Static or a Dynamic Framework
Difference Between Static Function and Singleton Class in Swift
Autolayout, Unable to Simultaneously Satisfy Constraints
iOS Horizontal Slideview with Vertical Menu
Allow Unverified Ssl Certificate in Uiwebview
Warning Frame for "Navigation Bar" Will Be Different at Run Time Appears in Xcode 8 Swift 3
How to Hide "-" (Delete) Button While Editing Uitableview
How to Call a View Controller Programmatically
Code Signing Is Required for Product Type Unit Test Bundle in Sdk iOS 8.0
iOS 7 and Later: Set Status Bar Style Per View Controller
Save and Retrieve Value via Keychain
Atos and Dwarfdump Won't Symbolicate My Address
Application Executable Is Missing a Required Architecture Armv6
How to Get Directions in Mkmapview Using a Built in Apple API