I am using CATransform3DMakeScale to resize a vector graphic in an iPad app. It is animated by default and I would like to be able to change the duration of this animation. Any advice?
If it's layers you want to adjust the duration try + setAnimationDuration:
Swift
class func setAnimationDuration(_ dur: CFTimeInterval)
Objective-C
+ (void)setAnimationDuration:(CFTimeInterval)duration
Sets the animation duration used by all animations within this
transaction group.
https://developer.apple.com/library/prerelease/ios/documentation/GraphicsImaging/Reference/CATransaction_class/index.html#//apple_ref/occ/clm/CATransaction/setAnimationDuration:
Related
I'm trying to implement a custom blur view where the blur radius can be animated, and the blur view can stack blending modes (CGBlendingMode or a CIFilter), all while preserving any animations/actions occurring in the background.
I tried UIVisualEffectView first, but the radius cannot be animated without accessing private APIs which would most likely lead to an app rejection.
The problem with taking a snapshot and applying the effects is that the view is static, and any movement in the background is covered up by the blur view.
I also took a look at FlexMonkey's Blurable, but I had similar results as the snapshot.
Any guidance would be really helpful.
Cheers
Edit: I added a gif to demonstrate what I'm trying to make. The red view moving left to right blurs and multiplies the content below it, while showing the animation occurring on the red/blue square behind it.
Blend modes are extremely tricky and I'm not sure it's possible to apply them to a live UIView (GPUImage might help here) but animating the blur radius (between 0 and UIVisualEffectView's full blur) is possible via this method:
You can animate from a nil effect to an effect like UIBlurEffectStyleDark so if we add an animation and then pause the layer's animations we can control the progress of the effect by adjusting the layer's timeOffset!
- (void) setupBlur {
// Setup the blur to start with no effect
self.blurredEffectView = [[UIVisualEffectView alloc] initWithEffect:nil];
// Add animation to desired blur effect
[UIView animateWithDuration:1.0 animations:^{
[self.blurredEffectView setEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
}];
// Pause layer animations
self.blurredEffectView.layer.speed = 0;
}
Adjust blur between 0.0 and 1.0 (animation duration):
- (void) adjustBlur:(CGFloat)blurIntensity {
self.blurredEffectView.layer.timeOffset = blurIntensity;
}
Note: this won't work on iOS 8 where UIBlurEffect animations aren't supported.
Currently, I'm using a UIVisualEffectView to apply a blur to an image.
I have a UIScrollView. As I pull down on the scrollView, in my "scrollViewDidScroll" method, I'm changing the alpha of the UIVisualEffectView. The current behavior of this is that the blur radius changes smoothly as I drag around in the view.
The problem is, of course, I'm not supposed to be doing this. Getting warnings about changing the alpha value of a UIVisualEffectView.
I've seen people say to do a smooth transition of blurring using an animation, like this here: How to fade a UIVisualEffectView and/or UIBlurEffect in and out?
However, I haven't seen anything that allows me to do this during, say a pan-gesture or something. I mean, if I set up an animation with a timed amount, all good. But doing this during a drag?
There is a way :)
As you've noticed, you can animate from a nil effect to an effect like UIBlurEffectStyleDark so if we add an animation and then pause the layer's animations we can control the progress of the effect by adjusting the layer's timeOffset!
- (void) setupBlur {
// Setup the blur to start with no effect
self.blurredEffectView = [[UIVisualEffectView alloc] initWithEffect:nil];
// Add animation to desired blur effect
[UIView animateWithDuration:1.0 animations:^{
[self.blurredEffectView setEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
}];
// Pause layer animations
self.blurredEffectView.layer.speed = 0;
}
Adjust blur between 0.0 and 1.0 (animation duration):
- (void) adjustBlur:(CGFloat)blurIntensity {
self.blurredEffectView.layer.timeOffset = blurIntensity;
}
Note: this won't work on iOS 8 where UIBlurEffect animations aren't supported.
I want to make rotation of CAShapeLayer with spring effect (like in UIView.animateWithDuration(_:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)) but on layer not on a view.
When the button is tapped its sublayer of main layer should rotate to 3*PI/4 and spring should bounce to 2*PI/3. Then, when button is tapped again, layer rotation should be done in reversed order than before: first bounce to 2*PI/3, then rotation to the initial position (before first rotation).
How I could do that? I cannot achieve it by UIView.animateWithDuration(_:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:) because layer's transform property is animatable by default.
I've tried changing CATransaction but it rotates only by one angle (without taking into consideration other rotation):
let rotation1 = CGAffineTransformRotate(CGAffineTransformIdentity, angle1)
let rotation2 = CGAffineTransformRotate(CGAffineTransformIdentity, angle2)
let transform = CGAffineTransformConcat(rotation1, rotation2)
CATransaction.begin()
CATransaction.setAnimationDuration(0.6)
self.plusLayer.setAffineTransform(transform)
CATransaction.commit()
Update
According to Duncan C post I try to use CASpringAnimation and I achive animation in one direction:
myLayer.setAffineTransform(CGAffineTransformMakeRotation(angle))
let spring = CASpringAnimation(keyPath: "transform.rotation")
spring.damping = 12.0
spring.fromValue = 2.0 * CGFloat(M_PI)
spring.toValue = 3.0 * CGFloat(M_PI_4)
spring.duration = 0.5
myLayer.addAnimation(spring, forKey: "rotation")
But how to reverse that animation on button tapped?
Thanks in advance for your help.
UIView block animation is for animating view properties. You could animate the button's transform (of type CGAffineTransform, a 2D transform) using UIView.animateWithDuration(_:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:
If you need to animate layer properties, though, you'll need to use Core Animation.
It seems Apple added (or made public) a spring CAAnimation in iOS 9. It doesn't seem to be in the Xcode docs however.
Check out this thread:
SpringWithDamping for CALayer animations?
I am trying to take a UIImageView and hide it gradually from bottom to top.
What is the best and most efficient way to do it in Objective-C?
I am looking into CABasicAnimation Class and Animation Class.
If you want know CoreAnimation deeply, I think you can use this:
CABasicAnimation *animationA=[CABasicAnimation animation];
animationA.keyPath=#"position.y";
animationA.fromValue=#0;
animationA.toValue=#250;
animationA.duration=3;
animationA.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[yourTestView.layer addAnimation:animationA forKey:#"basic"];
yourTestView.layer.position=CGPointMake(250, 50);
or if you want to only support IOS7, you can try learn UIAttachmentBehavior and UIDynamicItemBehavior to achieve more interactive animation.
All animations like this use Core Animation and can be done really simply using the block based animations.
For this you would do something like...
[UIView animateWithDuration:3
animations:^{
imageView.frame = CGRectMake(//the end frame of the image view
}];
This will then animate the change over the duration given. (3 seconds in this case).
There are other versions that you can find in the docs of UIView that give you more options like changing the animation curve or running some code on completion etc...
NOTE
This assumes you are not using Auto Layout. If you are using auto layout then the method is exactly the same but you need to change the constraints and then run [view layoutIfNeeded]; in the animations block.
I have a pre-defined sequence of colors and their durations (ms) that I would like to display in order (animate?) in a subview. In Android, I can use addFrame() with an AnimationDrawable to create an animation object. Is there something similar that will do this for me in iOS? (The total duration must be the sum of the individual color durations.) Thanks!
There are multiple ways you could do this. One example:
Loop over your colours and durations, say they are in an array of dictionaries (not required)
Keep a count of the duration so far
On each iteration, create an animation using + UIView animateWithDuration:delay:options:animations:completion: where the delay is the accumulated duration, the duration is the duration for this iteration and in the animation block:
The animation block sets the backgroundColor of the view
This approach has limitations as you can't stop or pause it.
Alternatively, use the completion block to trigger the next step of the animation. Now you can check if you should be stopping, and you don't need to accumulate the duration.
Or, use a CAPropertyAnimation key path animation. Now you can cancel at any point in the animation and you have full control over the speed and style of transition between colours.
The simplest way would be using a UIView object, and setting the background color for a certain duration. If the duration is the same you can use an NSTimer to fire repeatedly, setting the view to a new color each time.
Here is the simple example of animation using completion handler. _durations is an array of NSNumber objects representing color durations. _colors - array of UIColor instances.
- (void)animate
{
[UIView
animateWithDuration:[_durations[_currentColor] doubleValue]
animations:^{
self.view.backgroundColor = _colors[_currentColor++];
}
completion:^(BOOL finished) {
if (_currentColor < _colors.count) {
[self animate];
}
else {
_currentColor = 0;
}
}];
}