The most efficient way to draw text on a curve and animate it?

I assume that this is to make a line of separate CATextLayers, and then place them along the curve as necessary, and then animate. Because this is what I'm working on now, but he is losing Kerning. Here's how:

Why is my curved text not centered?

But is Core Text more sophisticated and able to avoid solid “drawing into the context” of bullshit that slows things down compared to the thin, medium way Core Animation and respects kerning? that is, to avoid drawRect: and all other aspects that significantly slow down the work, as with such a call to the screen:

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

Imagine a line of 200 characters bent around a circle, with the ability to animate the spacing between characters, hopefully at a stable 60 frames per second. This is possible using Core Animation, but this leads to the fact that breaking the string into separate characters and placing them around the circle with an equal interval, which leads to a complete loss of kerning information.

I am hoping for a way to do this without losing kerning information and still able to dynamically adjust the interval of 60 frames per second.

+6
source share
1 answer

Of course you can do it. However, with iOS 7, you don’t have to go all the way to Core Text. NSLayoutManager can handle it in many cases. See CurvyText Demo I wrote for iOS: PTL . You can drag all the control points and see the layout of the text along the curve.

To see how fast this layout can get in pure Core Text and Core Animation, see the PinchText Rich Text demo , the main text . This shows how to adjust the layout of the main text to respond to multi-touch, so the text seems to be bent towards your fingers. It includes examples of how to animate using Core Animation to get smooth settings (and even a little splash effect when you remove your finger).

I don’t quite understand what you mean by “the whole picture into contextual nonsense that slows everything down”. I draw them in context very, very fast (and Core Animation also draws a lot in contexts).

Bending text around a circle is easier than any of these demos. The trick is to compute points along your circle and use these points to translate and rotate your context before asking the layout manager to draw a glyph. Here is a drawText example from a CurvyTextView (which draws along a Bezier 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); } } 

The “magic” of this is to compute the transformations you need, which is done in offsetAtDistance:fromPoint:andOffset: pointForOffset: and angleForOffset: These procedures are much easier to write for a circle than the general Bezier curve, so this is probably a very good starting point. Please note that this code is not particularly optimized. It was designed for readability more than speed, but it still works very quickly on the iPad 3. If you need it to be faster, there are several methods , including a lot of preliminary calculation that can be done.

The PinchText demo is in pure Core Text and Core Animation, and it's quite a bit more complicated as it does all of its math acceleration (and really needs). I doubt you need this, because the layout problem is not that complicated. Some simple C can probably calculate everything you need in a lot of time. But the PinchText daemon shows how to let Core Animation manage transitions more nicely. Take a 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]; } } 

What happens here is that it animates the model data (the "scale" here is "how much it affects the layout, it has nothing to do with transformations"). needsDisplayForKey: indicates that when changing the data structure of the model, this layer must be redrawn. And he completely redefines and redraws himself in the context of each frame. Done correctly, it can be incredibly fast.

This code will hopefully help you get started. Don't push the book too much, but the demo version of CurvyText is widely discussed in iOS's “Pressing Constraints” in Chapter 21.

+12
source

Source: https://habr.com/ru/post/974511/


All Articles