我尝试将圆圈变成正方形,反之亦然,我几乎就在那里。然而,它没有像预期的那样动画。我想在一个正方形的所有角落同时进行动画/变形,但我得到的是以下内容:
我使用CAShapeLayer
和CABasicAnimation
来为形状属性设置动画。
以下是我创建圆圈路径的方法:
- (UIBezierPath *)circlePathWithCenter:(CGPoint)center radius:(CGFloat)radius
{
UIBezierPath *circlePath = [UIBezierPath bezierPath];
[circlePath addArcWithCenter:center radius:radius startAngle:0 endAngle:M_PI/2 clockwise:YES];
[circlePath addArcWithCenter:center radius:radius startAngle:M_PI/2 endAngle:M_PI clockwise:YES];
[circlePath addArcWithCenter:center radius:radius startAngle:M_PI endAngle:3*M_PI/2 clockwise:YES];
[circlePath addArcWithCenter:center radius:radius startAngle:3*M_PI/2 endAngle:M_PI clockwise:YES];
[circlePath closePath];
return circlePath;
}
这是方形路径:
- (UIBezierPath *)squarePathWithCenter:(CGPoint)center size:(CGFloat)size
{
CGFloat startX = center.x-size/2;
CGFloat startY = center.y-size/2;
UIBezierPath *squarePath = [UIBezierPath bezierPath];
[squarePath moveToPoint:CGPointMake(startX, startY)];
[squarePath addLineToPoint:CGPointMake(startX+size, startY)];
[squarePath addLineToPoint:CGPointMake(startX+size, startY+size)];
[squarePath addLineToPoint:CGPointMake(startX, startY+size)];
[squarePath closePath];
return squarePath;
}
我将圆形路径应用到我的一个View图层,设置填充等。它完美绘制。 然后在我的gestureRecognizer选择器中,我创建并运行以下动画:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.duration = 1;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fromValue = (__bridge id)(self.stateLayer.path);
animation.toValue = (__bridge id)(self.stopPath.CGPath);
self.stateLayer.path = self.stopPath.CGPath;
[self.stateLayer addAnimation:animation forKey:@"animatePath"];
正如您在circlePathWithCenter:radius:
和squarePathWithCenter:size:
中所注意到的,我遵循此处的建议(具有相同数量的细分和控制点):
Smooth shape shift animation
动画看起来比从上面的帖子好,但它仍然不是我想要实现的那个:(
我知道我可以使用简单的CALayer
执行此操作,然后设置适当的cornerRadius
级别,以便在方形/矩形之外创建一个圆形,然后设置动画cornerRadius
属性以更改它从一个圆圈到另一个圆形但如果甚至可以用CAShapeLayer
和path
动画做到这一点,我仍然非常好奇。
提前感谢您的帮助!
答案 0 :(得分:8)
在操场上玩了一会儿后,我注意到每个弧线都会向贝塞尔曲线路径添加两个线段,而不仅仅是一个。此外,呼叫closePath
还增加了两个。因此,为了保持段的数量一致,我最终在我的方路径中添加了假段。代码在Swift中,但我认为它并不重要。
func circlePathWithCenter(center: CGPoint, radius: CGFloat) -> UIBezierPath {
let circlePath = UIBezierPath()
circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI), endAngle: -CGFloat(M_PI/2), clockwise: true)
circlePath.addArcWithCenter(center, radius: radius, startAngle: -CGFloat(M_PI/2), endAngle: 0, clockwise: true)
circlePath.addArcWithCenter(center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI/2), clockwise: true)
circlePath.addArcWithCenter(center, radius: radius, startAngle: CGFloat(M_PI/2), endAngle: CGFloat(M_PI), clockwise: true)
circlePath.closePath()
return circlePath
}
func squarePathWithCenter(center: CGPoint, side: CGFloat) -> UIBezierPath {
let squarePath = UIBezierPath()
let startX = center.x - side / 2
let startY = center.y - side / 2
squarePath.moveToPoint(CGPoint(x: startX, y: startY))
squarePath.addLineToPoint(squarePath.currentPoint)
squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY))
squarePath.addLineToPoint(squarePath.currentPoint)
squarePath.addLineToPoint(CGPoint(x: startX + side, y: startY + side))
squarePath.addLineToPoint(squarePath.currentPoint)
squarePath.addLineToPoint(CGPoint(x: startX, y: startY + side))
squarePath.addLineToPoint(squarePath.currentPoint)
squarePath.closePath()
return squarePath
}
答案 1 :(得分:4)
我知道这是一个老问题,但这可能对某人有帮助。
我认为更好地设置角半径以获得此效果。
let v1 = UIView(frame: CGRect(x: 100, y: 100, width: 50, height: 50))
v1.backgroundColor = UIColor.green
view.addSubview(v1)
动画:
let animation = CABasicAnimation(keyPath: "cornerRadius")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
animation.fromValue = v1.layer.cornerRadius
animation.toValue = v1.bounds.width/2
animation.duration = 3
v1.layer.add(animation, forKey: "cornerRadius")
答案 2 :(得分:0)
我强烈推荐库CanvasPod,它还有一个预定义的“变形”动画,并且易于集成。您还可以在网站canvaspod.io上查看示例。
答案 3 :(得分:0)
根据@Danchoys的回答,这里是Objective-C。
信息是一个60px的按钮, infoVC 是下一个被推送的ViewController:
UIBezierPath * maskPath = [UIBezierPath new];
[maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(180) endAngle:DEGREES_TO_RADIANS(270) clockwise:true];
[maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(270) endAngle:DEGREES_TO_RADIANS(0) clockwise:true];
[maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(90) clockwise:true];
[maskPath addArcWithCenter:info.center radius:15.0f startAngle:DEGREES_TO_RADIANS(90) endAngle:DEGREES_TO_RADIANS(180) clockwise:true];
[maskPath closePath];
UIBezierPath * endPath = [UIBezierPath new];
[endPath moveToPoint:CGPointMake(0,0)];
[endPath addLineToPoint:endPath.currentPoint];
[endPath addLineToPoint:CGPointMake(w, 0)];
[endPath addLineToPoint:endPath.currentPoint];
[endPath addLineToPoint:CGPointMake(w, h)];
[endPath addLineToPoint:endPath.currentPoint];
[endPath addLineToPoint:CGPointMake(0, h)];
[endPath addLineToPoint:endPath.currentPoint];
[endPath closePath];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = info.bounds;
maskLayer.path = maskPath.CGPath;
_infoVC.view.layer.mask = maskLayer;
CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.fromValue = (id)maskPath.CGPath;
animation.toValue = (id)endPath.CGPath;
animation.duration = 0.3f;
[maskLayer addAnimation:animation forKey:nil];
[maskLayer setPath:endPath.CGPath];
答案 4 :(得分:0)
这对于制作录制按钮并想要原生iOS动画的人来说非常方便。
在您想要按钮的UIViewController中实例化此类。添加UITapGestureRecogniser
并在点击时调用animateRecordingButton
。
import UIKit
class RecordButtonView: UIView {
enum RecordingState {
case ready
case recording
}
var currentState: RecordingState = .ready
override init(frame: CGRect) {
super.init(frame: frame)
self.isUserInteractionEnabled = true
self.backgroundColor = .white
// My button is 75 points in height and width so this
// Will make a circle
self.layer.cornerRadius = 35
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func animateRecordingButton() {
var newRadius: CGFloat
var scale: CGFloat
switch currentState {
case .ready:
// The square radius
newRadius = 10
// Lets scale it down to 70%
scale = 0.7
currentState = .recording
case .recording:
// Animate back to cirlce
newRadius = 35
currentState = .ready
// Animate back to full scale
scale = 1
}
UIView.animate(withDuration: 1) {
self.layer.cornerRadius = newRadius
self.transform = CGAffineTransform(scaleX: scale, y: scale)
}
}
}