【问题标题】:How to animate a CALayer from a variable start point to a given end point如何将 CALayer 从变量起点动画到给定终点
【发布时间】:2019-11-24 10:27:31
【问题描述】:

CALayer 动画

我的应用程序的目的是在 TableView 中显示 ToDos/Tasks。所有任务都有一个开始值和一个结束值。

对于第一个任务,我想显示一个进度指示器,以便更好地了解剩余时间。对于背景,我的 ViewController 中有一个带有 autoLayout 约束的 UIView。我用于动画的 CALayer 是 backgroundView 的子层。 x 轴上图层的起点是变量,因此即使重新加载应用程序,计时器也设置正确。终点是一个绝对值(背景视图的全宽)。这些参数都可以正常工作,只是动画不起作用。我正在设置动画应该从哪里开始的值,以及剩下的持续时间,但 CALayer 不会移动。我尝试使用 UIView.animate 和 CABasicAnimation 操作图层,但在每种情况下,将图层设置为其起始位置后,动画都不会开始。

(https://ise-technology.com/cdn/stack-overflow/calayertimer/timer)

// func for setting setting the CALayer and the BackgroundView for the given values

func setTimerView(isActive: Bool, color: UIColor, animationDuration: Double){
    
    if isActive == true {
        
        configureBackgroundView(bool: true) // just sets the height for the background view
        
        backgroundTimerView.backgroundColor = color.withAlphaComponent(0.3)
        
        timerView.backgroundColor = color.cgColor
        
        setAnimationForDuration(duration: animationDuration)
        
    } else {
        configureBackgroundView(bool: false)
        timerView.backgroundColor = UIColor.clear.cgColor
    }
}


// func where the animation should be embedded 

func setAnimationForDuration(duration: Double) {

    let startPoint = setStartPoint(duration: duration)

    timerView.frame.origin.x = CGFloat(-startPoint)
    

    // after updating the origin X of the Layer to the current   position, its not possible to start an animation. My attempts to here place in this func


    let animation = CABasicAnimation()
    
    animation.duration = duration
    animation.toValue = timerView.frame.origin.x = 0 

    timerView.add(animation, forKey: nil)
     
}

【问题讨论】:

    标签: swift animation calayer


    【解决方案1】:

    您应该能够使用 CABasicAnimation 来完成您想要完成的任务。我已经在 Objective-C 中发布了我的答案,但我确信它也相对容易适应 Swift。

    我认为您还缺少几件事:

    设置图层的锚点和位置:

        self.progressLayer.position = CGPointZero;
        self.progressLayer.anchorPoint = CGPointZero;
    

    为 bounds.size.width 键路径设置 CABasicAnimation

    CABasicAnimation *progressAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size.width"];
    

    将填充模式设置为转发,完成后删除为 NO

        progressAnimation.fillMode = kCAFillModeForwards;
        [progressAnimation setRemovedOnCompletion:NO];
    

    这是一个仅使用一个视图控制器的示例,将进度条从中间点动画化到完整点:

    @interface ViewController ()
    @property (strong, nullable) IBOutlet UIView *backgroundView;
    @property (strong, nullable) CALayer *progressLayer;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.progressLayer = [[CALayer alloc] init];
        [self.progressLayer setFrame:CGRectMake(self.backgroundView.bounds.origin.x, self.backgroundView.bounds.origin.y, self.backgroundView.bounds.size.width / 2.0f, self.backgroundView.bounds.size.height)];
        self.progressLayer.position = CGPointZero;
        self.progressLayer.anchorPoint = CGPointZero;
        self.progressLayer.backgroundColor = [UIColor greenColor].CGColor;
        [self.backgroundView.layer addSublayer:self.progressLayer];
    }
    
    - (IBAction)animateProgress:(id)sender {
        [self.progressLayer removeAnimationForKey:@"progressAnimation"];
        CABasicAnimation *progressAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size.width"];
        progressAnimation.duration = 2.0f;
        progressAnimation.toValue = @(self.backgroundView.bounds.size.width);
        progressAnimation.fillMode = kCAFillModeForwards;
        [progressAnimation setRemovedOnCompletion:NO];
        [self.progressLayer addAnimation:progressAnimation forKey:@"progressAnimation"];
    }
    
    @end
    

    您应该能够在自定义表格视图单元格的 awakeFromNib + 一些触发动画的方法中执行类似的操作。

    上面的例子是这样的:

    【讨论】:

    • 非常感谢,我正在尝试快速重新创建它。你在哪里设置位置,我假设它在你设置 Frame 的 viewDidLoad() 中。对吗?
    • 是的,在我的示例中,我在 viewDidLoad 中设置了 progressLayer 的位置。如果你在 UITableViewCell 中使用它,我猜你可能想在 awakeFromNib 中设置它。
    【解决方案2】:
    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var backgroundView: UIView!
        
        var progressLayer : CALayer!
        
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.setUpLayer()
            
        }
        
        
        func setUpLayer(){
            
        
            let x = self.backgroundView.bounds.origin.x
            let y = self.backgroundView.bounds.origin.y
            let height = self.backgroundView.bounds.size.height
            let width  = self.backgroundView.bounds.size.width
            
            self.progressLayer = CALayer.init()
            self.progressLayer.frame = CGRect(x: x, y: y, width: 0, height: height)
            self.progressLayer.position = CGPoint.zero
            self.progressLayer.anchorPoint = CGPoint.zero;
            self.progressLayer.backgroundColor = UIColor.red.cgColor;
            self.backgroundView.layer.addSublayer(self.progressLayer)
         
        
        }
        
        @IBAction func buttonAction(_ sender: Any) {
            
         //   self.progressLayer.removeAnimation(forKey: "progressAnimation")
            
            var progressAnimation = CABasicAnimation(keyPath: "bounds.size.width")
             progressAnimation.duration = 2.0
            progressAnimation.toValue =  self.backgroundView.bounds.width
            progressAnimation.fillMode = .forwards
            
            progressAnimation.isRemovedOnCompletion = false
            
            self.progressLayer.add(progressAnimation, forKey: "progressAnimation")
    
            
        }
        
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-04
      • 2017-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多