以最高效的方式在曲线上绘制文本并为其制作动画?

Con*_*sed 6 core-animation kerning core-text ios

我猜这是用单个CATextLayers制作一个字符串,然后根据需要在曲线上定位它们,然后制作动画.因为那就是我现在的工作,但它失去了科宁.这是如何做:

为什么我的弯曲文字不能居中?

但是核心文本是否更具高效性并且能够避免整个"绘制成上下文"的废话,与精简,平均核心动画的做事方式相比,减慢一切,并尊重字距?即避免使用drawRect:以及所有其他方面都会大大减慢速度,例如以这种方式绘制到屏幕上:

https://github.com/darcyliu/CocoaSampleCode/tree/master/CoreTextArcCocoa

想象一下200个字符的字符串,围绕一个圆圈弯曲,能够动画字符之间的间距,希望稳定在60fps.这可以通过Core Animation实现,但这可以通过将字符串分解为单个字符并将它们以相等的间距放置在圆周围,这会导致字距调整信息完全丢失.

我希望有一种方法可以做到这一点,而不会丢失字距调整信息,仍然能够动态调整60fps的间距.

Rob*_*ier 12

当然,你可以做到这一点.但是,使用iOS 7,您无需一直向下到Core Text.NSLayoutManager在很多情况下可以处理它.请参阅我为iOS编写的CurvyText演示:PTL.您可以拖动所有控制点并沿曲线查看文本布局.

要了解此布局在纯Core Text和Core Animation中的速度有多快,请参阅Rich Text,Core TextPinchText演示.这一部分展示了如何调整Core Text布局以响应多点触控,因此文本似乎向您的手指弯曲.它包括如何使用Core Animation进行动画处理以获得平滑调整的示例(当您移开手指时甚至会产生一些小的"飞溅"效果).

我不太明白你的意思是"整个画面变成了一个让所有事情变慢的背景废话." 我非常非常快速地将这些绘制到一个上下文中(并且Core Animation也在很多情况下绘制到上下文中).

围绕圆圈弯曲文本比这些演示更容易.诀窍是计算沿着圆圈的点,并在要求布局管理器绘制字形之前使用这些点来平移和旋转上下文.这是drawTextCurvyTextView(沿着Bézier曲线绘制)的一个例子.

- (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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这样做的"魔术"是在计算你需要的变换,这是在做offsetAtDistance:fromPoint:andOffset:,pointForOffset:angleForOffset:.这些例程比圆形Bézier曲线更简单,因此这可能是一个非常好的起点.请注意,此代码未经过特别优化.它的设计目的是为了提高速度,但在iPad 3上仍然非常快.如果你需要它更快,有几种技术,包括可以完成的大量预先计算.

PinchText演示采用纯粹的核心文本和核心动画,并且由于它在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];
  }
}
Run Code Online (Sandbox Code Playgroud)

这里发生的是它为模型数据设置动画(这里的"比例"是"这种触摸对布局有多大影响;"它与变换无关).needsDisplayForKey:表示修改该模型数据结构时,该层需要重绘自身.它完全重新计算并重新绘制每一帧的上下文.做得对,这可以非常快.

这段代码应该有助于您入门.不要过度推动这本书,但是在推动极限第21章中广泛讨论了CurvyText演示.