2014-08-28 8 views
6

Immagino che sia quello di creare una stringa da singoli CATextLayers e quindi posizionarli come richiesto lungo la curva, quindi animare. Perché è quello che sto lavorando adesso, ma perde Kerning. Ecco come:Il modo più performante per disegnare il testo su una curva e animarlo?

Why isn't my curved text centering itself?

Ma è il nucleo di testo più performante e in grado di evitare l'intero "disegno in un contesto" sciocchezze che rallenta tutto giù rispetto alla magra, media modo Core Animation di fare le cose, e rispetto crenatura? cioè evitando drawRect: e tutti gli altri aspetti che le cose rallentare notevolmente, come in questo modo di disegno sullo schermo:

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

immaginare una stringa di 200 caratteri, piegate intorno ad un cerchio, con la possibilità di animare la spaziatura tra i personaggi, si spera in un 60fps stabile. Ciò è possibile con Core Animation, ma spezzando la stringa in singoli caratteri e posizionandoli attorno al cerchio con una spaziatura uguale, il che causa una perdita completa delle informazioni sui kern.

Sto sperando in un modo per farlo senza perdere le informazioni sui kern e ancora in grado di regolare dinamicamente la spaziatura a 60 fps.

risposta

12

Certo, puoi farlo. Con iOS 7, però, non è necessario andare fino in fondo a Core Text. NSLayoutManager può gestirlo in molti casi. Guarda la demo CurvyText che ho scritto per iOS:PTL. Puoi trascinare tutti i punti di controllo in giro e vedere il layout del testo lungo la curva.

Per visualizzare la velocità con cui questo layout è disponibile in Core Text e Core Animation, vedere la demo PinchText da Rich Text, Core Text. Questo mostra come regolare il layout del Core Text per rispondere al multi-touch, quindi il testo sembra piegarsi verso le dita. Include esempi di come animare con Core Animation per ottenere regolazioni fluide (e anche un piccolo effetto "splash" quando si rimuove il dito).

Non so cosa intendi con "l'intero disegno in un'assurdità del contesto che rallenta tutto". Traggo questi in un contesto molto, molto rapidamente (e Core Animation fa anche molto disegno in contesti).

Il testo di piegatura attorno a un cerchio è più semplice di una di queste demo. Il trucco consiste nel calcolare i punti lungo il cerchio e utilizzare questi punti per tradurre e ruotare il contesto prima di chiedere al gestore del layout di disegnare il glifo. Ecco un esempio drawText da CurvyTextView (che disegna lungo una curva di 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); 
    } 
} 

La "magia" di questo è nel calcolo delle trasformazioni cui avete bisogno, che è fatto in offsetAtDistance:fromPoint:andOffset:, pointForOffset: e angleForOffset:. Quelle routine sono molto più semplici da scrivere per un cerchio rispetto a una curva generica di Bézier, quindi questo è probabilmente un ottimo punto di partenza. Si noti che questo codice non è particolarmente ottimizzato. È stato progettato per la leggibilità più della velocità, ma è ancora molto veloce su un iPad 3. Se ne hai bisogno per essere più veloce, there are several techniques, tra cui un sacco di pre-calcolo che può essere fatto.

La demo di PinchText è in puro Core Text e Core Animation, ed è un po 'più complicata dal momento che esegue tutti i suoi calcoli in Accelerate (e ne ha davvero bisogno). Dubito che tu ne abbia bisogno dal momento che il tuo problema di layout non è così complicato. Una semplice C può probabilmente calcolare tutto ciò di cui hai bisogno in un sacco di tempo. Ma la demo di PinchText mostra come lasciare che Core Animation gestisca le transizioni in modo migliore.Guarda 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]; 
    } 
} 

Che cosa sta succedendo qui è che è animare i modello di dati ("scala" qui è "quanto costa questo tocco impatto del layout," non ha nulla a che fare con le trasformazioni). needsDisplayForKey: indica che quando la struttura dei dati del modello viene modificata, il livello deve ridisegnarsi. E ricalcola completamente e ridisegna se stesso nel suo contesto ogni fotogramma. Fatto correttamente, questo può essere incredibilmente veloce.

Questo codice dovrebbe spera di iniziare. Non spingere eccessivamente il libro, ma la demo di CurvyText è ampiamente discussa in iOS Pushing the Limits capitolo 21.

+1

Questo approccio, di tracciare efficacemente una riga di testo e quindi di utilizzarne la spaziatura per determinare i rapporti tra ciascun glifo l'uno sull'altro la curvatura della linea è probabilmente il modo ideale per risolvere il posizionamento dei CATextLayer composti da ciascun glifo, quindi sperimenterai con questo e ti farò sapere come funziona. GRAZIE!!! – Confused

+1

Questo metodo di tracciare il testo funziona meglio (per prestazioni) con CATextLayer come destinazione. Grazie Rob! – Confused

+0

@rob puoi controllare questo http://stackoverflow.com/questions/42383191/more-time-is-taken-to-display-nsattributo-string-with-custom-fonts – karthikeyan

Problemi correlati