如何为图层 shadowOpacity 设置动画?

Posted

技术标签:

【中文标题】如何为图层 shadowOpacity 设置动画?【英文标题】:How to animate layer shadowOpacity? 【发布时间】:2011-05-29 00:05:10 【问题描述】:

我有一个视图,我已将 layerOpacity 设置为 1。

    theView.layer.shadowOpacity = 1.0;

当视图位于屏幕下方时,这看起来不错。当我将此视图向上移动以与另一个有阴影的视图齐平时,它们看起来不太好。有没有办法可以将我图层上的shadowOpacity 设置为 0?我尝试使用动画块,但似乎这个属性是不可动画的。

编辑:请求无效的代码:

[UIView animateWithDuration:1.0 animations:^
    splitView2.layer.shadowOpacity = 0;
                 completion:NULL];

【问题讨论】:

来自 Apple 的文档:“@property float shadowOpacity 指定接收者阴影的不透明度。Animatable。”你能发布一些不起作用的代码吗? 在 UIView animateWithDuration 中不起作用 @JoeBlow:正确,这就是我写我发布的代码不起作用的原因。您必须直接使用 Core Animation,因为 UIView 没有为它提供隐式动画。 嗨,须藤!为了清楚起见,请注意@Costique 的评论:我正在回复该评论。干杯!感谢您提出这个方便的问题,它在下面得到了很好的答案。 【参考方案1】:

这将正常工作:

#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;

对于 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

【讨论】:

如果没有设置 vv.layer.shadowOpacity = 0.0;在最后一行,动画将完成,但之后它会跳回旧层 如果你想打开而不是关闭阴影,这两部分很重要:anim.removedOnCompletion = NO; anim.fillMode = kCAFillModeForwards; @moby 感谢您的评论。这是让这个答案发挥作用的关键。 可以用anim.removeOnCompletion应该去哪里更新代码sn-p吗? 重要提示:在 ios 模拟器中启用“调试 > 慢动画”时,通过此方法实现的动画可能不会以降低的速度运行。这个让我在杂草丛生了很长一段时间。具体来说,我认为我的动画设置不正确,因为我的自定义视图转换运行速度降低,但我的 CABasic 动画全速运行。【参考方案2】:

我把上面的代码放在了 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


用法如下:

animateLayer(\.shadowOffset, to: CGSize(width: 3, height: 3), duration:1)
animateLayer(\.shadowOpacity, to: 0.4, duration: 1)

它没有经过彻底的测试。但为我工作。 (也发帖here)

【讨论】:

【参考方案3】:

下面的代码对我有用

1)添加QuartzCore框架 2)导入QuartzCore框架

在需要的地方添加如下代码

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"];

它会起作用的。根据您的要求更改代码的格式

【讨论】:

【参考方案4】:

这是一个材料设计,类似于上面的一些动画 它也可以通过 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()

【讨论】:

以上是关于如何为图层 shadowOpacity 设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

如何为背景图像的更改设置动画?

如何为 geoJson 图层设置 zIndex 图层顺序?

如何为 CAShapeLayer 路径和填充颜色设置动画

如何为剪切路径设置动画

如何为 UITableViewCell 设置动画

如何为 CAGradientLayer 色点设置动画?