将CAShapeLayer圆圈设置为圆角三角形

bry*_*ark 7 animation cabasicanimation cashapelayer ios

我想为一个形状设置动画,因为它从圆形过渡到圆角三角形.

TL; DR:我如何动态显示CAShapeLayerpath两人之间CGPath的形状?我知道他们需要拥有相同数量的控制点,但我认为我这样做 - 这段代码出了什么问题?

开始和结束状态看起来像这样: 转换http://clrk.it/4vJS+

这是我到目前为止所尝试的内容:我正在使用a CAShapeLayer,并对其path属性进行动画处理.

根据文件(强调我的):

路径对象可以使用任何具体子类进行动画处理CAPropertyAnimation.路径将插值为"在线"点的线性混合; "离线"点可以非线性插值(例如,以保持曲线导数的连续性).如果两个路径具有不同数量的控制点或段,则结果未定义.

为了使圆和三角形具有相同数量的控制点,我将它们制成四角形:圆形是一个重圆角矩形,三角形"隐藏"一侧的第四个控制点.

这是我的代码:

self.view.backgroundColor = .blueColor()

//CREATE A CASHAPELAYER
let shape = CAShapeLayer()
shape.frame = CGRect(x: 50, y: 50, width: 200, height: 200)
shape.fillColor = UIColor.redColor().CGColor
self.view.layer.addSublayer(shape)

let bounds = shape.bounds

//CREATE THE SQUIRCLE
let squareRadius: CGFloat = CGRectGetWidth(shape.bounds)/2

let topCorner = CGPointMake(bounds.midX, bounds.minY)
let rightCorner = CGPointMake(bounds.maxX, bounds.midY)
let bottomCorner = CGPointMake(bounds.midX, bounds.maxY)
let leftCorner = CGPointMake(bounds.minX, bounds.midY)

let squarePath = CGPathCreateMutable()
let squareStartingPoint = midPoint(leftCorner, point2: topCorner)
CGPathMoveToPoint(squarePath, nil, squareStartingPoint.x, squareStartingPoint.y)
addArcToPoint(squarePath, aroundPoint: topCorner, onWayToPoint: rightCorner, radius: squareRadius)
addArcToPoint(squarePath, aroundPoint: rightCorner, onWayToPoint: bottomCorner, radius: squareRadius)
addArcToPoint(squarePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: squareRadius)
addArcToPoint(squarePath, aroundPoint: leftCorner, onWayToPoint: topCorner, radius: squareRadius)
CGPathCloseSubpath(squarePath)
let square = UIBezierPath(CGPath: squarePath)

//CREATE THE (FAKED) TRIANGLE
let triangleRadius: CGFloat = 25.0

let trianglePath = CGPathCreateMutable()
let triangleStartingPoint = midPoint(topCorner, point2: rightCorner)

let startingPoint = midPoint(topCorner, point2: leftCorner)
CGPathMoveToPoint(trianglePath, nil, startingPoint.x, startingPoint.y)
let cheatPoint = midPoint(topCorner, point2:bottomCorner)
addArcToPoint(trianglePath, aroundPoint: topCorner, onWayToPoint: cheatPoint, radius: triangleRadius)
addArcToPoint(trianglePath, aroundPoint: cheatPoint, onWayToPoint: bottomCorner, radius: triangleRadius)
addArcToPoint(trianglePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: triangleRadius)
addArcToPoint(trianglePath, aroundPoint: leftCorner, onWayToPoint: topCorner, radius: triangleRadius)
CGPathCloseSubpath(trianglePath)
let triangle = UIBezierPath(CGPath: trianglePath)


shape.path = square.CGPath
Run Code Online (Sandbox Code Playgroud)

......以及之后,在viewDidAppear:

let animation = CABasicAnimation(keyPath: "path")
animation.fromValue = self.square.CGPath
animation.toValue = self.triangle.CGPath
animation.duration = 3
self.shape.path = self.triangle.CGPath
self.shape.addAnimation(animation, forKey: "animationKey")
Run Code Online (Sandbox Code Playgroud)

我有两个快速的小函数,使代码更清晰:

func addArcToPoint(path: CGMutablePath!, aroundPoint: CGPoint, onWayToPoint: CGPoint, radius: CGFloat) {
    CGPathAddArcToPoint(path, nil, aroundPoint.x, aroundPoint.y, onWayToPoint.x, onWayToPoint.y, radius)
}

func midPoint(point1: CGPoint, point2: CGPoint) -> CGPoint {
    return CGPointMake((point1.x + point2.x)/2, (point1.y + point2.y)/2)
}
Run Code Online (Sandbox Code Playgroud)

我目前的结果如下:

三角形到方

注意:我试图从一个非常圆的方块构建圆,试图在矢量形状中获得相同数量的控制点.在上面的GIF中,角半径已经减小,使转换更加明显.

你觉得怎么样?我怎么能达到这个效果呢?

And*_*hak 6

你没有得到相同数量的控制点,因为addArcToPoint()如果路径的当前点和它的第一个参数相等,则跳过创建线段.

从其文档(强调我的):

如果当前点和弧的第一个切点(起点)不相等,则Quartz会将当前点的直线段附加到第一个切点.

你的三角形代码中的这两个调用不会产生线段,而制作squircle的相应调用将:

addArcToPoint(trianglePath, aroundPoint: cheatPoint, onWayToPoint: bottomCorner, radius: triangleRadius)
addArcToPoint(trianglePath, aroundPoint: bottomCorner, onWayToPoint: leftCorner, radius: triangleRadius)
Run Code Online (Sandbox Code Playgroud)

但是,您可以通过调用手动创建行CGPathAddLineToPoint.你可以使用CGPathApplierFunction它来检查你的工作,这将让你枚举控制点.


还~~~我可能会建议旋转一个显示链接并编写一个为每个指定所需形状的函数,这t ? [0, 1]可能是一个更清晰,更易于维护的解决方案.