Reputation: 13
My App's purpose is to display ToDos/Tasks in a TableView. All the tasks have a start and an end value.
For the first task I want to display a progress indicator for a good overview, about the time that's left. For the Background I have an UIView with autoLayout constraints in my ViewController. The CALayer, that I am using for the animation is a sublayer from the backgroundView. The start point of the layer on the x-axis is variabel, so even with a reload of the app, the timer is set correctly. The end point is an absolut value (the full width of the background view). Those parameters are all working perfectly, just the animation does not work. I'm setting the values from where the animation should start, and the duration which is left, but the CALayer is not going to move. I have tried to manipulate the Layer with UIView.animate and with CABasicAnimation but in every case, after setting the layer to its start position, the animation does not start.
(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)
}
Upvotes: 1
Views: 2076
Reputation: 1152
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")
}
}
Upvotes: 1
Reputation: 2595
You should be able to use CABasicAnimation for what you're attempting to accomplish. I've posted my answer in Objective-C, but I'm sure it is relatively easy to adapt it for Swift as well.
A couple of additional things that I believe you're missing:
self.progressLayer.position = CGPointZero;
self.progressLayer.anchorPoint = CGPointZero;
CABasicAnimation *progressAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size.width"];
progressAnimation.fillMode = kCAFillModeForwards;
[progressAnimation setRemovedOnCompletion:NO];
Here's an example using just one view controller an animating a progress bar from the halfway point to the full point:
@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
You should be able to do something similar in a custom tableview cell's awakeFromNib + some method to trigger the animation.
Here's what the example above looks like:
Upvotes: 1