如何在不改变大小和位置的情况下旋转矩形?
How to rotate a rectangle without changing its size and position?
我可以画出和上图一样的路径,但是如何让矩形的边框旋转呢?
圆形很容易旋转,但是矩形呢?该示例以 osx 编写,您还可以为 iOS 和 osx 提供此示例。谢谢
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[self setWantsLayer:YES];
self.layer.backgroundColor = [NSColor blackColor].CGColor;
// Drawing code here.
//NSBezierPath *path = [NSBezierPath bezierPathWithRect:NSMakeRect(10, 10, self.frame.size.width -20, self.frame.size.height -20)];
[self round];
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(10, 10, self.frame.size.width -20, self.frame.size.height -20) xRadius:2 yRadius:2];
shapeLayer = [CAShapeLayer layer];
shapeLayer.lineWidth = 2;
shapeLayer.fillColor = [NSColor clearColor].CGColor;
shapeLayer.strokeColor = [NSColor redColor].CGColor;
shapeLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10],
[NSNumber numberWithInt:5],nil];
shapeLayer.path = [self copyQuartzPathFromNSBezierPath:path];
[self.layer addSublayer:shapeLayer];
}
- (void)round
{
[CATransaction begin];
CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotation.toValue = [NSNumber numberWithFloat:-M_PI*2];
rotation.duration = 0.5f;
rotation.repeatCount = 1;
[CATransaction setCompletionBlock:^{
}];
[shapeLayer addAnimation:rotation forKey:@"rotation"];
shapeLayer.anchorPoint = CGPointMake(0.5, 0.5);
[CATransaction commit];
}
- (CGPathRef)copyQuartzPathFromNSBezierPath:(NSBezierPath *)bezierPath
{
NSInteger i, numElements;
// Need to begin a path here.
CGPathRef immutablePath = NULL;
// Then draw the path elements.
numElements = [bezierPath elementCount];
if (numElements > 0) {
CGMutablePathRef path = CGPathCreateMutable();
NSPoint points[3];
BOOL didClosePath = YES;
for (i = 0; i < numElements; i++) {
switch ([bezierPath elementAtIndex:i associatedPoints:points]) {
case NSMoveToBezierPathElement:
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
break;
case NSLineToBezierPathElement:
CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
didClosePath = NO;
break;
case NSCurveToBezierPathElement:
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
didClosePath = NO;
break;
case NSClosePathBezierPathElement:
CGPathCloseSubpath(path);
didClosePath = YES;
break;
}
}
// Be sure the path is closed or Quartz may not do valid hit detection.
if (!didClosePath) {
CGPathCloseSubpath(path);
}
immutablePath = CGPathCreateCopy(path);
CGPathRelease(path);
}
return immutablePath;
}
编辑
我发现一个解决方案是使用 svg
并从 Webview 加载它。
主要代码是:
<style type="text/css">
path {
transition:all 1s linear;
animation-name:ring;
animation-duration:60s;
animation-timing-function: linear;
animation-iteration-count:infinite;
}
@keyframes ring {
from {
stroke-dashoffset:0;
}
to {
stroke-dashoffset:2000;
}
}
</style>
您尝试创建的效果通常称为 "marching ants"。
我建议不要像您问题中的代码那样使用 -drawRect:
,而是建议对 CAShapeLayer
的 lineDashPhase
进行动画处理。一旦您知道要搜索什么,网上就会有大量示例和解释。例如:
我可以画出和上图一样的路径,但是如何让矩形的边框旋转呢? 圆形很容易旋转,但是矩形呢?该示例以 osx 编写,您还可以为 iOS 和 osx 提供此示例。谢谢
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[self setWantsLayer:YES];
self.layer.backgroundColor = [NSColor blackColor].CGColor;
// Drawing code here.
//NSBezierPath *path = [NSBezierPath bezierPathWithRect:NSMakeRect(10, 10, self.frame.size.width -20, self.frame.size.height -20)];
[self round];
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(10, 10, self.frame.size.width -20, self.frame.size.height -20) xRadius:2 yRadius:2];
shapeLayer = [CAShapeLayer layer];
shapeLayer.lineWidth = 2;
shapeLayer.fillColor = [NSColor clearColor].CGColor;
shapeLayer.strokeColor = [NSColor redColor].CGColor;
shapeLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10],
[NSNumber numberWithInt:5],nil];
shapeLayer.path = [self copyQuartzPathFromNSBezierPath:path];
[self.layer addSublayer:shapeLayer];
}
- (void)round
{
[CATransaction begin];
CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotation.toValue = [NSNumber numberWithFloat:-M_PI*2];
rotation.duration = 0.5f;
rotation.repeatCount = 1;
[CATransaction setCompletionBlock:^{
}];
[shapeLayer addAnimation:rotation forKey:@"rotation"];
shapeLayer.anchorPoint = CGPointMake(0.5, 0.5);
[CATransaction commit];
}
- (CGPathRef)copyQuartzPathFromNSBezierPath:(NSBezierPath *)bezierPath
{
NSInteger i, numElements;
// Need to begin a path here.
CGPathRef immutablePath = NULL;
// Then draw the path elements.
numElements = [bezierPath elementCount];
if (numElements > 0) {
CGMutablePathRef path = CGPathCreateMutable();
NSPoint points[3];
BOOL didClosePath = YES;
for (i = 0; i < numElements; i++) {
switch ([bezierPath elementAtIndex:i associatedPoints:points]) {
case NSMoveToBezierPathElement:
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
break;
case NSLineToBezierPathElement:
CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
didClosePath = NO;
break;
case NSCurveToBezierPathElement:
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
didClosePath = NO;
break;
case NSClosePathBezierPathElement:
CGPathCloseSubpath(path);
didClosePath = YES;
break;
}
}
// Be sure the path is closed or Quartz may not do valid hit detection.
if (!didClosePath) {
CGPathCloseSubpath(path);
}
immutablePath = CGPathCreateCopy(path);
CGPathRelease(path);
}
return immutablePath;
}
编辑
我发现一个解决方案是使用 svg
并从 Webview 加载它。
主要代码是:
<style type="text/css">
path {
transition:all 1s linear;
animation-name:ring;
animation-duration:60s;
animation-timing-function: linear;
animation-iteration-count:infinite;
}
@keyframes ring {
from {
stroke-dashoffset:0;
}
to {
stroke-dashoffset:2000;
}
}
</style>
您尝试创建的效果通常称为 "marching ants"。
我建议不要像您问题中的代码那样使用 -drawRect:
,而是建议对 CAShapeLayer
的 lineDashPhase
进行动画处理。一旦您知道要搜索什么,网上就会有大量示例和解释。例如: