Asymmetric body text on iOS

I want to write text in a way that can take any form. Right now I can draw inverted text in it:

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); 

This creates the following:

Flipped text in asymmetric shape

I understand that iOS has an inverted coordinate system. Most solutions add these two lines before drawing:

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

But this produces the following:

Text is now written left-right right-side-up but out of path bounds

So why does this technique not work? In every example I saw, this method is used when the text is displayed in something symmetrical or with clipping or on OS X. If we draw the text in a symmetrical form, our calls to CGContextTranslateCTM() and CGContextScaleCTM() make sense. Calling CGContextTranslateCTM(context, 0, rect.size.height) moves the beginning of the first letter up. Calling CGContextScaleCTM(context, 1, -1) changes the direction of Y. If we change the direction of Y to a symmetrical shape, it will not change. Unfortunately, my figures are not symmetrical.

Here is what I reviewed, but refused

  • Draw the figures and numbers at the same scale (upside down), then flip the UIImageView behind it somehow (1)
  • Do not make calls to change the scale or translate CTM. Flip the text matrix with CGContextSetTextMatrix() so that the text is drawn from left to right, from bottom to top, and from right to top. Determine how many extra characters remain in the form after defining the line for the shape. Turn over the words (now he will draw from top to bottom, from right to left, from top to right). Add spaces for each additional character. Now for each CTLine , somehow turn the words over again (now it will draw from top to bottom, from left to right, from top to right) (2)

Why did I leave them

(1) I cannot flip my images. They should always be right.

(2) This may be redundant for a simple solution that someone knows

+3
source share
1 answer

I determined a solution

 // 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)]; 

Now everything is drawn from top to bottom, left to right, right up.

Core Text correctly laid out on asymmetric shape in iOS

+5
source

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


All Articles