【问题标题】:UIView animateWithDuration doesn't animate cornerRadius variationUIView animateWithDuration 不会为cornerRadius 变化设置动画
【发布时间】:2011-08-22 08:01:00
【问题描述】:

我正在尝试为UIView 实例layercornerRadius 的变化设置动画,但cornerRadius 的变化会立即发生。

代码如下:

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 100, 100)];
view.layer.masksToBounds = YES;
view.layer.cornerRadius = 10.0;
[UIView animateWithDuration:1.0 animations:^{
    
    [view.layer.cornerRadius = 0.0;
    
}];

感谢所有愿意给我建议的人。

编辑:

我设法使用Core Animation 为该属性设置动画,使用CABasicAnimation

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.fromValue = [NSNumber numberWithFloat:10.0f];
animation.toValue = [NSNumber numberWithFloat:0.0f];
animation.duration = 1.0;
[viewToAnimate.layer addAnimation:animation forKey:@"cornerRadius"];
[animation.layer setCornerRadius:0.0];

【问题讨论】:

  • 试试这个,让你的动画坚持新的价值观:animation.removedOnCompletion = NO;animation.fillMode = kCAFillModeForwards;
  • @MohammadAbdurraafay 不,请不要。这是使动画“坚持”的错误方式。
  • @DavidRönnqvist 为什么不应该使用animation.removedOnCompletion = NO;?您在此处或您的回答中均未提供其他建议。
  • @DavidRönnqvist 链接未附加。
  • @user1763532 让我们再试一次:my answer here 解释了removeOnCompletion = NO 的一些问题,并提供了另一种解决方案。

标签: ios uiview core-animation uiviewanimation cornerradius


【解决方案1】:

tl;dr:圆角半径在animateWithDuration:animations: 中不可设置动画。


文档中关于视图动画的内容。

正如“查看 iOS 编程指南”中的 section on Animations 所说

UIKit 和 Core Animation 都提供对动画的支持,但每种技术提供的支持程度各不相同。在 UIKit 中,动画是使用 UIView 对象执行的

属性的完整列表,您可以使用旧版本进行动画处理

[UIView beginAnimations:context:];
[UIView setAnimationDuration:];
// Change properties here...
[UIView commitAnimations];

或更新的

[UIView animateWithDuration:animations:];

(您正在使用的)是:

  • 框架
  • 界限
  • 居中
  • 变换(CGAffineTransform,不是 CATransform3D)
  • 阿尔法
  • 背景颜色
  • 内容拉伸

如您所见,cornerRadius 不在列表中。

有些混乱

UIView 动画实际上只用于动画视图属性。让人困惑的是,你还可以在 UIView 动画块内的图层上为相同的属性设置动画,即 frame、bounds、position、opacity、backgroundColor。所以人们看到 animateWithDuration 内部的图层动画,并相信他们可以为其中的任何视图属性设置动画。

同一节继续说:

在您想要执行更复杂的动画或 UIView 类不支持的动画的地方,您可以使用 Core Animation 和视图的底层来创建动画。由于视图和图层对象错综复杂地链接在一起,因此对视图图层的更改会影响视图本身。

往下几行,您可以阅读 Core Animation 动画属性列表,您可以在其中看到这个:

  • 图层的边框(包括图层的角是否圆角)

所以要为cornerRadius 设置动画,您需要使用您在更新的问题(和答案)中已经说过的 Core Animation。我只是添加了试图解释为什么会这样。


一些额外的说明

当人们阅读说明animateWithDuration 是推荐的动画方式的文档时,很容易相信它正在尝试替换 CABasicAnimation、CAAnimationGroup、CAKeyframeAnimation 等,但实际上并非如此。它取代了您在上面看到的beginAnimations:context:commitAnimations

【讨论】:

  • 好答案。用于指出所有文档的道具。
  • 完美答案。帮助很大。非常感谢。
  • 这在 iOS 11 中有所改变,请参考我的回答
【解决方案2】:

我使用这个扩展来动画圆角半径的变化:

extension UIView
{
    func animateCornerRadius(from: CGFloat, to: CGFloat, duration: CFTimeInterval)
    {
        CATransaction.begin()
        let animation = CABasicAnimation(keyPath: "cornerRadius")
        animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
        animation.fromValue = from
        animation.toValue = to
        animation.duration = duration
        CATransaction.setCompletionBlock { [weak self] in
            self?.layer.cornerRadius = to
        }
        layer.add(animation, forKey: "cornerRadius")
        CATransaction.commit()
    }
}

【讨论】:

  • 工作得非常好。您实际上并不需要 from 字段,因为它应该始终是 layer.cornerRadius
  • 谢谢,在我的 UIView.animate 块中运行良好,即将 UIView 的移动与cornerRadius 的变化相结合
  • 从 iOS 11 开始可以动画化 useyourloaf.com/blog/masked-and-animated-corners
【解决方案3】:

CornerRadius 属性是可动画的

工作代码如下

//层初始化

let imageLayer = CALayer() 
imageLayer.frame = CGRect(x: 0, y: 0.0, width: tenPercent, height: tenPercent)
imageLayer.contents = imageNew.cgImage
imageLayer.masksToBounds = true

// 动画初始化

let animationCornerRadius = CABasicAnimation(keyPath: "cornerRadius")
animationCornerRadius.beginTime =  0.01
animationCornerRadius.duration = CFTimeInterval(5)
animationCornerRadius.fromValue = 1
animationCornerRadius.toValue = tenPercent / 2
animationCornerRadius.fillMode = .forwards
animationCornerRadius.isRemovedOnCompletion = false
imageLayer.add(animationCornerRadius , forKey: "cornerRadius")

【讨论】:

    【解决方案4】:

    iOS 10 开始,您实际上可以为cornerRadius 设置动画:

    UIViewPropertyAnimator(duration: 3.0, curve: .easeIn) {
        square.layer.cornerRadius = 20
    }.startAnimation()
    

    【讨论】:

    • 它适用于 iOS 10+。
    【解决方案5】:

    你可以在这里实现 UIView 动画:http://maniacdev.com/2013/02/ios-uiview-category-allowing-you-to-set-up-customizable-animation-properties

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
    animation.duration = DURATION;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.toValue = @(NEW_CORNER_RADIUS);
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = NO;
    [view.layer addAnimation:animation forKey:@"setCornerRadius:"];
    

    【讨论】:

    • 由于 iOS 11cornerRadius 是动画属性
    【解决方案6】:

    您可以通过在您的视图类中实现-[actionForLayer:forKey] 使该属性在+[UIView animateWithDuration:] 中具有动画效果。请参阅this question 了解如何操作的示例。

    【讨论】:

      【解决方案7】:

      可以为圆角半径变化设置动画,但唯一的方法是使用 CABasicAnimation。希望这可以帮助那里的人。

      【讨论】:

        【解决方案8】:

        【讨论】:

        • 嗯...如果您使用旧的动画方法,它会起作用...但是如果您尝试使用 Apple 建议的方法,则它不会动画。
        • @singingAtom animateWithDuration: 和 CABasicAnimations 实际上不是一回事,因此没有新的或旧的方法。 animateWithDuration 不是核心动画的一部分,只能为视图属性设置动画(cornerRadius 是图层属性)。 animateWithDuration 取代的真正旧方法是 [UIView beginAnimations:context:] 和 [UIView commitAnimation],它们的工作方式与新方法完全相同。 Apple 建议将 animateWithDuration: 用于视图属性,并继续说您应该将 Core Animation 用于更高级的动画。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多