2014-08-28 1 views
6

개별 CATextLayers에서 문자열을 만든 다음 필요에 따라 곡선을 따라 배치 한 다음 애니메이션을 적용하는 것이 좋습니다. 그게 내가 지금 일하는 것이지만 커닝을 잃어 버리게된다. 방법은 다음과 같습니다커브에 텍스트를 그리고 애니메이션을 적용하는 가장 효과적인 방법은 무엇입니까?

Why isn't my curved text centering itself?

그러나이 코어 텍스트보다 확대됨과 린에 비해 아래로 모든 것을 느리게 전체 "문맥으로 그리기"넌센스를 방지 할 수있는, 코어 애니메이션 일을하는 방법과 존경을 의미 커닝? 즉의 drawRect을 방지 :

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

애니메이션 할 수있는 기능, 원 주위에 구부러진 200 자,의 문자열을 상상 : 화면에 그리기의 방법으로 크게 느린 것을 아래로, 다른 모든 측면 문자 사이의 간격, 안정적으로 60fps에서. 이것은 Core Animation에서 가능하지만 문자열을 개별 문자로 분리하여 동일한 간격으로 원 둘레에 배치하면 커닝 정보가 완전히 손실됩니다.

커닝 정보를 잃지 않고 60fps에서 동적으로 간격을 조정할 수있는 방법을 찾고 있습니다.

답변

12

물론 가능합니다. iOS 7을 사용하면 Core Text로 이동할 필요가 없습니다. NSLayoutManager은 많은 경우이를 처리 할 수 ​​있습니다. iOS:PTL에 대해 작성한 CurvyText 데모를 참조하십시오. 모든 제어점을 드래그하여 곡선을 따라 텍스트 레이아웃을 볼 수 있습니다.

이 레이아웃이 순수 코어 텍스트 및 코어 애니메이션에서 얼마나 빨리 표시되는지 보려면 Rich Text, Core TextPinchText 데모를 참조하십시오. 이것은 멀티 터치에 응답하도록 코어 텍스트 레이아웃을 조정하는 방법을 보여 주므로 텍스트가 손가락을 향해 구부러진 것처럼 보입니다. 여기에는 Core Animation으로 애니메이션을 적용하여 부드럽게 조정하는 방법과 손가락을 뺄 때 작은 "튀김 (splash)"효과까지 포함하는 예제가 포함되어 있습니다.

나는 "모든 것을 늦추는 문맥 어리석은 말투로 전체를 그리는"것이 무슨 뜻인지 잘 모르겠습니다. 이러한 상황을 매우 빠르게 컨텍스트에 그려줍니다 (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:, pointForOffset:angleForOffset:에서 이루어집니다 당신이 필요로하는 변환을 계산이다. 이러한 루틴은 일반적인 베 지어 곡선보다 원을 그리는 것이 훨씬 간단하므로이 방법이 매우 좋은 출발점 일 것입니다. 이 코드는 특별히 최적화되지 않았습니다. 가독성을 높이기 위해 설계되었지만 iPad 3에서는 여전히 빠릅니다. 더 빨리 수행해야하는 경우 사전 계산이 많이 필요한 there are several techniques 등이 있습니다.

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]; 
    } 
} 

이는 모델 데이터를 애니메이션 점이다 ("규모"여기 "얼마입니까이 터치 영향 레이아웃;"이 변환과는 아무 상관이 없습니다). needsDisplayForKey:은 해당 모델 데이터 구조가 수정 될 때 레이어가 자체적으로 다시 그려야 함을 나타냅니다. 그리고 그것은 모든 프레임에서 그 컨텍스트로 완전히 재 계산되고 다시 그려집니다. 올바르게 완료하면이 작업이 매우 빨라질 수 있습니다.

이 코드를 사용하면 쉽게 시작할 수 있습니다. 책을 지나치게 강요하지는 않지만 CurvyText 데모는 iOS Pushing the Limits 21 장에서 광범위하게 논의됩니다.

+1

효과적으로 텍스트 줄을 그린 다음 해당 줄 간격을 사용하여 각 글립 문자의 비율을 선의 곡률은 각각의 글리프로 구성된 CATextlayers의 배치를 해결하는 데 이상적인 방법 일 수 있습니다. 따라서이 점을 실험하고 어떻게 작동하는지 알려 드리겠습니다. 고맙습니다!!! – Confused

+1

텍스트를 배치하는이 방법은 CATextLayer를 대상으로 (성능 향상을 위해) 가장 잘 작동합니다. 롭 감사합니다! – Confused

+0

@rob 확인할 수 있습니까? http://stackoverflow.com/questions/42383191/more-time-is-taken-to-display-nsattributed-string-with-custom-fonts – karthikeyan

관련 문제