当然,你可以这样做。不过,在 iOS 7 中,您无需一直深入到 Core Text。NSLayoutManager
在很多情况下都可以处理。请参阅我为iOS:PTL编写的CurvyText演示。您可以拖动所有控制点并沿曲线查看文本布局。
要了解这种布局在纯 Core Text 和 Core Animation 中的速度有多快,请参阅 Rich Text 中的PinchText演示,Core Text。这个展示了如何调整 Core Text 布局以响应多点触控,因此文本似乎向您的手指弯曲。它包括如何使用 Core Animation 制作动画以获得平滑调整的示例(甚至当您移开手指时也会产生小的“飞溅”效果)。
我不太明白你所说的“整个画成一个让一切都慢下来的废话”是什么意思。我非常非常快地将它们绘制到上下文中(Core Animation 也做了很多绘制到上下文中)。
围绕一个圆圈弯曲文本比这些演示中的任何一个都容易。诀窍是沿着你的圆圈计算点,并在要求布局管理器绘制字形之前使用这些点来平移和旋转你的上下文。这是 CurvyTextView 的一个例子drawText
(它沿着贝塞尔曲线绘制)。
- (void)drawText {
if ([self.attributedString length] == 0) { return; }
NSLayoutManager *layoutManager = self.layoutManager;
CGContextRef context = UIGraphicsGetCurrentContext();
NSRange glyphRange;
CGRect lineRect = [layoutManager lineFragmentRectForGlyphAtIndex:0
effectiveRange:&glyphRange];
double offset = 0;
CGPoint lastGlyphPoint = self.P0;
CGFloat lastX = 0;
for (NSUInteger glyphIndex = glyphRange.location;
glyphIndex < NSMaxRange(glyphRange);
++glyphIndex) {
CGContextSaveGState(context);
CGPoint location = [layoutManager locationForGlyphAtIndex:glyphIndex];
CGFloat distance = location.x - lastX; // Assume single line
offset = [self offsetAtDistance:distance
fromPoint:lastGlyphPoint
andOffset:offset];
CGPoint glyphPoint = [self pointForOffset:offset];
double angle = [self angleForOffset:offset];
lastGlyphPoint = glyphPoint;
lastX = location.x;
CGContextTranslateCTM(context, glyphPoint.x, glyphPoint.y);
CGContextRotateCTM(context, angle);
[layoutManager drawGlyphsForGlyphRange:NSMakeRange(glyphIndex, 1)
atPoint:CGPointMake(-(lineRect.origin.x + location.x),
-(lineRect.origin.y + location.y))];
CGContextRestoreGState(context);
}
}
其“魔力”在于计算您需要的变换,这是在和中完成offsetAtDistance:fromPoint:andOffset:
的。这些例程比一般的贝塞尔曲线更容易为圆编写,所以这可能是一个很好的起点。请注意,此代码并未特别优化。它的设计是为了可读性而不是速度,但它在 iPad 3 上仍然非常快。如果你需要它更快,有几种技术,包括可以完成的大量预先计算。pointForOffset:
angleForOffset:
PinchText 演示是纯 Core Text 和 Core Animation 中的,并且相当复杂,因为它在 Accelerate 中完成所有数学运算(并且确实需要)。我怀疑您是否需要它,因为您的布局问题并不复杂。一些简单的 C 语言可能可以在很长一段时间内计算出您需要的所有内容。但是 PinchText 演示确实展示了如何让 Core Animation 更漂亮地管理过渡。看addTouches:inView:scale:
:
- (void)addTouches:(NSSet *)touches inView:(UIView *)view scale:(CGFloat)scale
{
for (UITouch *touch in touches) {
TouchPoint *touchPoint = [TouchPoint touchPointForTouch:touch inView:view scale:scale];
NSString *keyPath = [self touchPointScaleKeyPathForTouchPoint:touchPoint];
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:keyPath];
anim.duration = kStartTouchAnimationDuration;
anim.fromValue = @0;
anim.toValue = @(touchPoint.scale);
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self addAnimation:anim forKey:keyPath];
[self.touchPointForIdentifier setObject:touchPoint forKey:touchPoint.identifier];
}
}
这里发生的事情是它正在为模型数据设置动画(这里的“比例”是“这种触摸对布局有多大影响;”它与变换无关)。needsDisplayForKey:
表示当该模型数据结构被修改时,该层需要重绘自身。它在每一帧都完全重新计算并将自己重新绘制到它的上下文中。如果做得正确,这可能会非常快。
这段代码应该可以帮助您入门。不要过度推动本书,但 CurvyText 演示在iOS Pushing the Limits第 21 章中进行了广泛讨论。