在曲线上绘制文本并设置动画效果的最有效方法? [英] Most performant way to draw text on a curve, and animate it?

查看:115
本文介绍了在曲线上绘制文本并设置动画效果的最有效方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我猜想是要从各个CATextLayers中创建一个字符串,然后根据需要将它们沿着曲线放置,然后进行动画处理。因为这就是我现在要从事的工作,但是却失去了紧缩。方法如下:

I'm guessing that it's to make a string out of individual CATextLayers and then position them as required along the curve, then animate. Because that's what's I've got working now, but it loses Kerning. Here's how:

为什么我的弧形文本不居中?

但是Core Text的性能更高并且能够避免整个拖入上下文的废话与精益,卑鄙的Core Animation处事方式和尊重字距调整相比,一切都下降了吗?即避免使用drawRect:以及所有其他会大大降低速度的方面,例如以这种方式绘制到屏幕上:

But is Core Text more performant and able to avoid the whole "drawing into a context" nonsense that slows everything down compared to the lean, mean Core Animation way of doing things, and respect kerning? i.e. avoiding drawRect: and all other aspects that greatly slow things down, as in this manner of drawing to the screen:

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

想象一下一个200个字符的字符串,该字符绕一个圆弯曲,能够动画化字符之间的间距,希望能达到60fps的稳定水平。使用Core Animation可以做到这一点,但这是通过将字符串分解为单个字符并将它们以相等的间距放置在圆圈周围,从而导致字距调整信息完全丢失。

Imagine a string of 200 characters, bent around a circle, with the ability to animate the spacing between characters, hopefully at a stable 60fps. This is possible with Core Animation, but that's by breaking the string up into individual characters and placing them around the circle with equal spacing, which causes a complete loss of kerning information.

我希望能够做到这一点,而又不会丢失字距调整信息,并且仍然能够动态调整60fps的间距。

I'm hoping for a way to do this without losing the kerning information and still being able to dynamically adjust spacing at 60fps.

推荐答案

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

Sure, you can do that. With iOS 7, you don't need to go all the way down to Core Text, though. NSLayoutManager can handle it in many cases. See the CurvyText demo that I wrote for iOS:PTL. You can drag all the control points around and see the text layout along the curve.

要了解这种布局在纯Core Text和Core Animation中获得多快的效果,请参见 PinchText 演示http://cocoaheads.tv/core-text-crash-course-by-rob-napier/ rel = noreferrer>富文本,核心文本。此示例显示了如何调整核心文本布局以响应多点触摸,因此文本似乎向您的手指弯曲。它包括有关如何使用Core Animation进行动画处理以进行平滑调整的示例(甚至当您松开手指时也可以产生小的飞溅效果)。

To see just how fast this layout can get in pure Core Text and Core Animation, see the PinchText demo from Rich Text, Core Text. This one shows how to adjust Core Text layout to respond to multi-touch, so the text seems to bend towards your fingers. It includes examples of how to animate with Core Animation to get smooth adjustments (and even a small "splash" effect when you remove your finger).

我不太清楚知道您的意思是将整个图纸拖入上下文废话会使一切变慢。我非常非常快地将它们绘制到上下文中(Core Animation也将大量绘制到上下文中)。

I don't quite know what you mean by "the whole drawing into a context nonsense that slows everything down." I draw these into a context very, very quickly (and Core Animation also does a lot of drawing into contexts).

将文本弯曲成圆圈比这两个都容易演示。技巧是计算沿圆的点,并在要求布局管理器绘制字形之前使用这些点平移和旋转上下文。这是CurvyTextView中的 drawText 示例(沿着贝塞尔曲线绘制)。

Bending text around a circle is easier than either of these demos. The trick is to calculate the points along your circle, and use those points to translate and rotate your context before asking the layout manager to draw the glyph. Here's an example drawText from CurvyTextView (which draws along a Bézier curve).

- (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: pointForOffset: angleForOffset中完成:。与普通的贝塞尔曲线相比,这些例程编写一个圆要容易得多,因此这可能是一个很好的起点。请注意,此代码没有特别优化。它旨在提高可读性而不是速度,但是在iPad 3上仍然非常快。如果需要更快,请有几种技术,其中包括许多可以完成的预先计算。

The "magic" of this is in calculating the transforms you need, which is done in offsetAtDistance:fromPoint:andOffset:, pointForOffset: and angleForOffset:. Those routines are much simpler to write for a circle than a generic Bézier curve, so this is probably a very good starting point. Note that this code is not particularly optimized. It was designed for readability more than speed, but it is still very fast on an iPad 3. If you need it to be faster, there are several techniques, including a lot of pre-calculating that can be done.

PinchText演示使用的是纯Core Text和Core Animation,并且因为它在Accelerate中(并且确实需要)完成所有数学运算,所以它要复杂得多。我怀疑您是否需要布局,因为布局问题没有那么复杂。一些简单的C可能会在很长时间内计算出您所需的一切。但是PinchText演示确实显示了如何让Core Animation更精美地管理过渡。看看 addTouches:inView:scale:

The PinchText demo is in pure Core Text and Core Animation, and is quite a bit more complicated since it does all of its math in Accelerate (and really needs to). I doubt you need that since your layout problem isn't that complicated. Some straightforward C can probably calculate everything you need in plenty of time. But the PinchText demo does show how to let Core Animation manage transitions more beautifully. Look at 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:表示修改模型数据结构时,该图层需要重绘自身。并且它在每帧都完全重新计算并重新绘制到其上下文中。正确完成后,这可能会非常快。

What's going on here is that it's animating the model data ("scale" here is "how much does this touch impact the layout;" it has nothing to do with transforms). needsDisplayForKey: indicates that when that model data structure is modified, the layer needs to redraw itself. And it completely recomputes and redraws itself into its context every frame. Done correctly, this can be incredibly fast.

该代码有望使您入门。不会过度推销这本书,但是中广泛讨论了CurvyText演示。 iOS突破极限第21章。

This code should hopefully get you started. Not to overly push the book, but the CurvyText demo is discussed extensively in iOS Pushing the Limits chapter 21.

这篇关于在曲线上绘制文本并设置动画效果的最有效方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆