Основной текст с асимметричной формой на iOS

Я хочу написать текст по контуру, который может принимать любую форму. Прямо сейчас я могу нарисовать в нем перевернутый текст:

NSArray *coordinates = ...;

CGMutablePathRef pathRef = [self objectPathGivenCoordinates:coordinates];

... // Draw the shapes

// Now draw the text    
CGContextSetTextMatrix(context, CGAffineTransformIdentity);

NSAttributedString* attString = [[NSAttributedString alloc] initWithString:@"0,1,2..."];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attString);
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, [attString length]), pathRef, NULL);
CTFrameDraw(frame, context);

Это производит следующее:

Перевернутый текст в асимметричной форме

Я так понимаю, что в iOS перевернутая система координат. Большинство решений добавляют эти две линии перед рисованием:

CGContextTranslateCTM(context, 0, rect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

Но это дает следующее:

Текст теперь пишется слева направо справа вверх, но вне границ пути

Так почему же эта техника не работает? В каждом примере, который я видел, этот метод используется, когда текст отображается в чем-то симметричном, с отсечением или в OS X. Если мы рисуем текст в симметричной форме, наши вызовы CGContextTranslateCTM() и CGContextScaleCTM() имеют смысл. Вызов CGContextTranslateCTM(context, 0, rect.size.height) перемещает начало первой буквы наверх. Вызов CGContextScaleCTM(context, 1, -1) меняет направление Y на противоположное. Если мы изменим направление Y на симметричную фигуру, оно не изменится. К сожалению, мои формы не симметричны.

Вот что я рассмотрел, но отказался

  • Нарисуйте фигуры и числа в одном масштабе (оба вверх ногами), затем как-нибудь переверните UIImageView за ним (1)
  • Не звоните, чтобы изменить масштаб или перевести CTM. Переверните текстовую матрицу с помощью CGContextSetTextMatrix(), чтобы текст отображался слева направо, снизу вверх и справа вверх. Определите, сколько дополнительных символов осталось в фигуре после определения строки для фигуры. Поменяйте местами слова (теперь он будет рисовать сверху вниз, справа налево, правой стороной вверх). Добавьте пробелы для каждого лишнего символа. Теперь для каждого CTLine как-нибудь снова поменяйте местами слова (теперь он будет рисовать сверху вниз, слева направо, правой стороной вверх) (2)

Почему я бросил их

(1) Я не могу переворачивать свои изображения. Они всегда должны быть правильными

(2) Это может быть излишним для простого решения, которое знает кто-то другой.


person Rey Gonzales    schedule 09.12.2013    source источник
comment
Используйте CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1, -1)) вместо CGAffineTransformIdentity   -  person Emmanuel    schedule 09.12.2013
comment
См. Мое второе соображение в конце вопроса   -  person Rey Gonzales    schedule 09.12.2013


Ответы (1)


Я нашел решение

// Flip the coordinates so that the object is drawn as if it were mirrored along the x-axis
// coordinates = @[CGPointMake(1, 2), CGPointMake(9, 17), CGPointMake(41, 3), ...]
NSArray *flippedCoordinates = [coordinates map:^id(id object) {
     CGPoint value;
     [object getValue:&value];
     CGPoint point = value;

     point.y = point.y * (-1) + rect.size.height;

     return [NSValue value:&point withObjCType:@encode(CGPoint)];
}];

// Generate a CGPathRef using the new coordinates
CGMutablePathRef pathRef = CGPathCreateMutable();
CGPathMoveToPoint(pathRef, NULL, [[flippedCoordinates objectAtIndex:0] CGPointValue].x + .5 [[flippedCoordinates objectAtIndex:0] CGPointValue].y + .5);
for(NSValue *arrayValue in flippedCoordinates) {
    CGPoint point = [arrayValue CGPointValue];
    CGPathAddLineToPoint(pathRef, NULL, point.x, point.y);
}
CGPathCloseSubpath(pathRef);

// Draw the object
// ...

// Draw the text as if it were on OS X
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
NSAttributedString* attString = [[NSAttributedString alloc] initWithString:@"0,1,2,..." attributes:@{(NSString *)kCTForegroundColorAttributeName : textColor}];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attString);
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, [attString length]), pathRef, NULL);
CTFrameDraw(frame, context);

CFRelease(frame);
CFRelease(frameSetter);
CFRelease(pathRef);

// And, for the magic touch, flip the whole view AFTER everything is drawn
[self.layer setAffineTransform:CGAffineTransformMakeScale(1, -1)];

Теперь все рисуется сверху вниз, слева направо, правой стороной вверх.

Основной текст правильно размещен на асимметричной форме в iOS

person Rey Gonzales    schedule 12.12.2013