How to Animate Bordercolor Change in Swift

How to animate borderColor change in swift

I don't know why, but for some reason calling:

color.fromValue = sender.layer.borderColor

doesn't work. The color isn't being read correctly or something. I changed it to:

let color = CABasicAnimation(keyPath: "borderColor");
color.fromValue = UIColor.greenColor().CGColor;
color.toValue = UIColor.redColor().CGColor;
color.duration = 2;
color.repeatCount = 1;
sender.layer.addAnimation(color, forKey: "color and width");

And then things started working as expected.

Swift Change circular border color with animation

You can stroke the button's path using the following code snippet.

@IBAction func buttonTapped(_ sender: UIButton) {
let storkeLayer = CAShapeLayer()
storkeLayer.fillColor = UIColor.clear.cgColor
storkeLayer.strokeColor = UIColor.red.cgColor
storkeLayer.lineWidth = 2

// Create a rounded rect path using button's bounds.
storkeLayer.path = CGPath.init(roundedRect: sender.bounds, cornerWidth: 5, cornerHeight: 5, transform: nil) // same path like the empty one ...
// Add layer to the button
sender.layer.addSublayer(storkeLayer)

// Create animation layer and add it to the stroke layer.
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = CGFloat(0.0)
animation.toValue = CGFloat(1.0)
animation.duration = 1
animation.fillMode = kCAFillModeForwards
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
storkeLayer.add(animation, forKey: "circleAnimation")
}

This snippet creates something like this:

Sample Image

Animating button border in swift

Features such as the borderColor and borderWidth are properties of the button's layer. That tells you that you must use core animation of the layer - not view animation, as your code tries to do - to animate such features. It works perfectly well; in this animation, I demonstrate what happens when you use core animation to animation the borderWidth and the cornerRadius together:

Sample Image

Animation of the borderColor would work similarly.

Animate CALayer border change

Both borderColor and borderWidth are animatable properties but since you are doing this in a view subclass outside of an UIView animation block, implicit animations (those that happen automatically when you change a value) are disabled.

If you want to animate these properties then you can do an explicit animation with a CABasicAnimation. Since you are animating two properties on the same layer, you can add them both to an animation group and only configure the duration, timing, etc. once. Note that the explicit animations are purely visual, the model value (the actual property) doesn't change when you add them. That is why you both configure the animation and set the model value.

CABasicAnimation *color = [CABasicAnimation animationWithKeyPath:@"borderColor"];
// animate from red to blue border ...
color.fromValue = (id)[UIColor redColor].CGColor;
color.toValue = (id)[UIColor blueColor].CGColor;
// ... and change the model value
self.layer.borderColor = [UIColor blueColor].CGColor;

CABasicAnimation *width = [CABasicAnimation animationWithKeyPath:@"borderWidth"];
// animate from 2pt to 4pt wide border ...
width.fromValue = @2;
width.toValue = @4;
// ... and change the model value
self.layer.borderWidth = 4;

CAAnimationGroup *both = [CAAnimationGroup animation];
// animate both as a group with the duration of 0.5 seconds
both.duration = 0.5;
both.animations = @[color, width];
// optionally add other configuration (that applies to both animations)
both.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

[self.layer addAnimation:both forKey:@"color and width"];

If you look at the documentation for CABasicAnimation under the section "Setting Interpolation values", you will see that it's not necessary to specify both the toValue and the fromValue like I did, so the code could be made slightly shorter. However, for clarity and readability (especially when you are starting with Core Animation) being more explicit can help you (and your coworker) understand the code.

How to flash/change a UIButton borderColor with animation

Hope this can help

    targetButton.layer.borderWidth = 8.0
let color: CABasicAnimation = CABasicAnimation(keyPath: "borderColor")
color.fromValue = UIColor.clearColor().CGColor
color.toValue = UIColor.greenColor().CGColor
color.duration = 0.5
color.autoreverses = true
self.targetButton.layer.borderColor = UIColor.clearColor().CGColor
self.targetButton.layer.addAnimation(color, forKey: "")

sorry, I forgot to set button border width.
you can try again.

Animate progress with filling the color of the border width of a UIImageView layer

UIImageView is meant to show the images. I would not suggest changing it's behaviour. Even though you subclass the UIImageView and try to draw something in it, the drawRect of it will not get called. Let the imageView be imageView and use UIView for the rest
I suggest you to subclass the UIView and then draw a bezier path in it and animate the bezier path curve, You can later add the imageview to the uiview .

UIView subclass:

- (void)drawRect:(CGRect)rect {
[self drawImageHolderViewFrame:rect startAngle:_startAngle];
}

- (void)drawImageHolderViewFrame: (CGRect)frame startAngle: (CGFloat)startAngle
{
CGRect ovalRect = CGRectMake(CGRectGetMinX(frame) , CGRectGetMinY(frame) , frame.size.width-10, frame.size.height-10);
UIBezierPath* ovalPath = [UIBezierPath bezierPath];
[ovalPath addArcWithCenter: CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect)) radius: CGRectGetWidth(ovalRect) / 2 startAngle: -91 * M_PI/180 endAngle: -startAngle * M_PI/180 clockwise: YES];
[UIColor.redColor setStroke];
ovalPath.lineWidth = 2;
[ovalPath stroke];
}

viewController class:

-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
_imageHolderView=[[MyView alloc]initWithFrame:CGRectMake(20, 20, 100, 100)];
_imageHolderView.startAngle=90;
_imageHolderView.backgroundColor=[UIColor clearColor];
[self.view addSubview: _imageHolderView];
[self startTImer];
}

-(void)startTImer{
NSTimer *timer=[NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(animateBorder) userInfo:nil repeats:YES];
}

-(void)animateBorder{
if (_startAngle<=-270) {
_startAngle=90;
}
_startAngle--;
_imageHolderView.startAngle=_startAngle;
[_imageHolderView setNeedsDisplay];
}

This would give you:

Sample Image

Now you can add the imageview as a subview to the view you just created.

Sample Image

Swift, ios 10 UIButton Border

I did find the final answer.
Thanks to krotov who tried to help!

 class BorderButton: UIButton {

override init(frame: CGRect){
super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

var colorPast: Bool = true

override var isHighlighted: Bool {
didSet {
if isHighlighted && colorPast {
borderDissapear(highlighted: isHighlighted)
colorPast = false
} else if !isHighlighted && !colorPast {
borderDissapear(highlighted: isHighlighted)
colorPast = true
}
}
}

func borderDissapear (highlighted: Bool) {
let animation = CABasicAnimation(keyPath: "borderColor")
animation.duration = 0.1
animation.autoreverses = false
animation.repeatCount = 1
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
if highlighted {
animation.fromValue = self.layer.borderColor?.copy(alpha: 1)
animation.toValue = self.layer.borderColor?.copy(alpha: 0.3)
} else if !highlighted {
animation.fromValue = self.layer.borderColor?.copy(alpha: 0.3)
animation.toValue = self.layer.borderColor?.copy(alpha: 1)
}
self.layer.add(animation, forKey: "borderColor")
}
}

UITextField border animation

Those properties are not animatable. Yu'll need to remove your text field borders and create some other UIView with the borders you want in back of your text field. Also set it's alpha property to 0.0 and animate it to 1.0 when you need. (alpha property is animatable, so this will do the work for you).

EDIT.

tmp.layer.borderColor= [UIColor redColor].CGColor;
tmp.layer.borderWidth = 1.0f;
tmp.alpha = 0.0;
//somewhere here should be the [someView addSubview:tmp];
//and after that should go the [someView addSubview:yourTextFieldView];

//somewhere later in your code, when you need the animation to happen
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2];
tmp.alpha = 1.0;
[UIView commitAnimations];

Also you may use the so-called one-stage animation like so:

[UIView animateWithDuration:2.0 animations:^{
tmp.alpha = 1.0;
}];

How can I animate border width / color of UICollectionViewCells during layout transition?

As it turns out, changes to layer properties are not caught by the animation methods on UIView like animateWithDuration. So they have to be added to the layer using CAAnimation. So, in applyLayoutAttributes, I do something like this:

CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"borderColor"];
anim.fromValue = (id)[UIColor clearColor].CGColor;
anim.toValue = (id)[UIColor lightGrayColor].CGColor;
self.layer.borderColor = [UIColor lightGrayColor].CGColor;
anim.duration = [CATransaction animationDuration];
anim.timingFunction = [CATransaction animationTimingFunction];
[self.layer addAnimation:anim forKey:@"myAnimation"];

Thanks to this answer for the trick about getting the right animation duration.



Related Topics



Leave a reply



Submit