How to animate layer shadowOpacity?
Solution 1
This will work properly:
#import <QuartzCore/CAAnimation.h>
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
anim.fromValue = [NSNumber numberWithFloat:1.0];
anim.toValue = [NSNumber numberWithFloat:0.0];
anim.duration = 1.0;
[vv.layer addAnimation:anim forKey:@"shadowOpacity"];
vv.layer.shadowOpacity = 0.0;
For Swift 3.0:
let animation = CABasicAnimation(keyPath: "shadowOpacity")
animation.fromValue = layer.shadowOpacity
animation.toValue = 0.0
animation.duration = 1.0
view.layer.add(animation, forKey: animation.keyPath)
view.layer.shadowOpacity = 0.0
Solution 2
I've put above code in a little extension of UIView:
extension UIView {
func animateLayer<Value>(_ keyPath: WritableKeyPath<CALayer, Value>, to value:Value, duration: CFTimeInterval) {
let keyString = NSExpression(forKeyPath: keyPath).keyPath
let animation = CABasicAnimation(keyPath: keyString)
animation.fromValue = self.layer[keyPath: keyPath]
animation.toValue = value
animation.duration = duration
self.layer.add(animation, forKey: animation.keyPath)
var thelayer = layer
thelayer[keyPath: keyPath] = value
}
}
Usage like:
animateLayer(\.shadowOffset, to: CGSize(width: 3, height: 3), duration:1)
animateLayer(\.shadowOpacity, to: 0.4, duration: 1)
It's not thoroughly tested. but worked for me. (Also posted here)
Solution 3
The below code work for me
1)Add QuartzCore frame work 2)Import QuartzCore frame work
Add the following Code in the required place
UIImageView * glowimageview = [[[UIImageView alloc]init]autorelease];
[glowimageview setFrame:CGRectMake(500,400,200,200)];
[glowimageview setImage:[UIImage imageNamed:@"144.png"]];
[sender addSubview:glowimageview];
glowimageview.layer.shadowColor = [UIColor redColor].CGColor;
glowimageview.layer.shadowRadius = 10.0f;
glowimageview.layer.shadowOpacity = 1.0f;
glowimageview.layer.shadowOffset = CGSizeZero;
CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
shadowAnimation.duration=1.0;
shadowAnimation.repeatCount=HUGE_VALF;
shadowAnimation.autoreverses=YES;
shadowAnimation.fromValue = [NSNumber numberWithFloat:1.0];
shadowAnimation.toValue = [NSNumber numberWithFloat:0.0];
[glowimageview.layer addAnimation:shadowAnimation forKey:@"shadowOpacity"];
It will works. Change the format of the code as per your requirement
Solution 4
Here's a material design like take on some of the above with animations It's also available here as framework through Carthage https://github.com/sevenapps/SVNMaterialButton
public init(frame: CGRect, color: UIColor) {
super.init(frame: frame)
self.backgroundColor = color
self.layer.masksToBounds = false
self.layer.borderWidth = 1.0
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOpacity = 0.8
self.layer.shadowRadius = 8
self.layer.shadowOffset = CGSize(width: 8.0, height: 8.0)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("This class is not set up to be instaciated with coder use init(frame) instead")
}
public override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.frame.height / 4
}
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.animate(to: 0.5, and: CGSize(width: 5.0, height: 5.0), with: 0.5)
super.touchesBegan(touches, with: event)
}
public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.animate(to: 0.8, and: CGSize(width: 8.0, height: 8.0), with: 0.5)
super.touchesBegan(touches, with: event)
}
private func animate(to opacity: Double, and offset: CGSize, with duration: Double){
CATransaction.begin()
let opacityAnimation = CABasicAnimation(keyPath: "shadowOpacity")
opacityAnimation.toValue = opacity
opacityAnimation.duration = duration
opacityAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
opacityAnimation.fillMode = kCAFillModeBoth
opacityAnimation.isRemovedOnCompletion = false
let offsetAnimation = CABasicAnimation(keyPath: "shadowOffset")
offsetAnimation.toValue = offset
offsetAnimation.duration = duration
offsetAnimation.timingFunction = opacityAnimation.timingFunction
offsetAnimation.fillMode = opacityAnimation.fillMode
offsetAnimation.isRemovedOnCompletion = false
self.layer.add(offsetAnimation, forKey: offsetAnimation.keyPath!)
self.layer.add(opacityAnimation, forKey: opacityAnimation.keyPath!)
CATransaction.commit()
}
Related videos on Youtube
sudo rm -rf
Hi, I'm Jonathan. I'm an iOS & Mac developer with a specialty in Core Animation. I created this Stack Overflow account back when I knew absolutely nothing about programming. Thus this profile serves as a documentation of my journey to where I am today. Glad I was able to help people out along the way. Keep up with me elsewhere: GitHub: https://github.com/jwilling Twitter. https://twitter.com/willing Blog: http://jwilling.com
Updated on December 09, 2020Comments
-
sudo rm -rf over 3 years
I have a view on which I've set the layerOpacity to 1.
theView.layer.shadowOpacity = 1.0;
This looks fine when the view is farther down the screen. When I move this view up to be flush with another view that has a shadow, they don't look good. Is there a way I can animate the
shadowOpacity
on my layer to be 0? I tried using an animation block but it seems as if this property is not animatable.EDIT: Request for code that doesn't work:
[UIView animateWithDuration:1.0 animations:^{ splitView2.layer.shadowOpacity = 0;} completion:NULL];
-
Costique over 13 yearsFrom Apple's docs: "
@property float shadowOpacity
Specifies the opacity of the receiver’s shadow. Animatable." Can you post some code where that doesn't work? -
Fattie over 9 yearsdoesn't work in UIView animateWithDuration
-
sudo rm -rf over 9 years@JoeBlow: Correct, that's why I wrote that the code I posted doesn't work. You'll have to use Core Animation directly, since
UIView
doesn't provide an implicit animation for it. -
Fattie over 9 yearshi Sudo! To be clear, notice @Costique 's comment: I was replying to that comment. Cheers! Thanks for asking this handy question, which resulted in the good answer below.
-
-
Admin over 13 yearsif you not set the vv.layer.shadowOpacity = 0.0; at the last line, the animation will be done but after that it will jump back to the old layer
-
Snowman over 9 yearsIf you want to animate the shadow on rather than off, these two pieces are important:
anim.removedOnCompletion = NO; anim.fillMode = kCAFillModeForwards;
-
BigSauce about 9 years@moby Thanks for your comment. That is an essential point to getting this answer to work.
-
fatuhoku over 8 yearsCan the code snippet be updated with where
anim.removeOnCompletion
should go? -
Scott Ahten almost 7 yearsImportant note: animations implemented via this method might not run at a reduced speed when "Debug > Slow Animations" is enabled in the iOS simulator. This one sent me off in the weeds for quite some time. Specifically, I thought I had set my animation up incorrectly because my custom view transition was running at reduced speed, but my CABasic animation ran at full speed.