objective guide framework developer apis iphone quartz-graphics

iphone - guide - swift ios documentation



Dibujo de texto rotado con NSString drawInRect (5)

Encontré esta respuesta sobre cómo dibujar texto girado con NSString drawInRect :, pero no estoy seguro de cómo funciona, ya que solo me funciona en cierto modo: https://discussions.apple.com/thread/1779814?start=0&tstart=0

Mi código se ve como:

CGContextSaveGState(context); CGContextDrawLinearGradient(context, gradient, CGPointMake(0, centY - halfWidth), CGPointMake(0, centY + halfWidth), 0); // Add text CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); NSString *str = @"some test string"; CGAffineTransform transform1 = CGAffineTransformMakeRotation(M_PI/4); CGContextConcatCTM(context, transform1); CGContextTranslateCTM(context, 0, 0); UIFont *font = [UIFont systemFontOfSize:16.0]; [str drawInRect:CGRectMake(0, 0, 200, 100) withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UIBaselineAdjustmentNone];

Entonces, cuando uso esto, veo que el texto se dibuja 45 grados debajo del eje x. Quiero dibujar el texto verticalmente a lo largo de mi linealgradient. Así que pensé que podía hacerlo usando M_PI / 2 para 90 grados. Aunque no veo mi texto. He intentado diferentes transformaciones para la rotación, y solo algunas parecen funcionar como M_PI / 4 y M_PI / 8. Pensaría que si usara -M_PI / 4 tendría el texto 45 grados por encima del eje x y M_PI / 2 estaría 90 grados por debajo del eje x. Pero ambos se levantan sin nada.

¿Alguna idea? Gracias.


Aquí hay una versión actualizada y simplificada de la respuesta de KoNEW. Conserva el estado del contexto de los gráficos como un bono. Esta es también una función simple en lugar de una extensión de String.

func drawRotatedText(_ text: String, at p: CGPoint, angle: CGFloat, font: UIFont, color: UIColor) { // Draw text centered on the point, rotated by an angle in degrees moving clockwise. let attrs = [NSFontAttributeName: font, NSForegroundColorAttributeName: color] let textSize = text.size(attributes: attrs) let c = UIGraphicsGetCurrentContext()! c.saveGState() // Translate the origin to the drawing location and rotate the coordinate system. c.translateBy(x: p.x, y: p.y) c.rotate(by: angle * .pi / 180) // Draw the text centered at the point. text.draw(at: CGPoint(x: -textSize.width / 2, y: -textSize.height / 2), withAttributes: attrs) // Restore the original coordinate system. c.restoreGState() }


Creo que lo que está sucediendo es que estás rotando el texto a una ubicación fuera de la vista porque gira el contexto girando sobre el origen.

Después de la rotación, debe hacer una traducción para mover el contexto nuevamente a la vista. En el siguiente ejemplo, roto el contexto en sentido antihorario 90 grados. Luego traduzco la tx del contexto la distancia de la altura.

- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); // Create the gradient CGColorRef startColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0].CGColor; CGColorRef endColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1.0].CGColor; NSArray *colors = [NSArray arrayWithObjects:(id)startColor, (id)endColor, nil]; CGFloat locations[] = { 0.0, 1.0 }; CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef) colors, locations); CGContextDrawLinearGradient(context, gradient, CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y), CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y + rect.size.height), 0); // Create text CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); NSString *string = @"some test string"; UIFont *font = [UIFont systemFontOfSize:16.0]; // Rotate the context 90 degrees (convert to radians) CGAffineTransform transform1 = CGAffineTransformMakeRotation(-M_PI_2); CGContextConcatCTM(context, transform1); // Move the context back into the view CGContextTranslateCTM(context, -rect.size.height, 0); // Draw the string [string drawInRect:rect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft]; // Clean up CGGradientRelease(gradient); CGColorSpaceRelease(colorSpace); CGContextRestoreGState(context); }

Tenga en cuenta que también puede obtener el tamaño de cómo se representará la cadena, lo que puede ayudar a hacer cálculos para la alineación del texto.

CGSize stringSize = [string sizeWithFont:font];


Gracias por esta publicación, y la respuesta de Chris , y la respuesta de Arkadiusz en otra publicación .

Finalmente, UILabel este problema con una subclase de UILabel , llamada MyVerticalLabel , y hago que dibuje texto vertical.

@implementation MyVerticalLabel // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code CGContextRef context = UIGraphicsGetCurrentContext(); CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI_2); CGContextConcatCTM(context, transform); CGContextTranslateCTM(context, -rect.size.height, 0); // The drawing rect should be applied with transform to. CGRect newRect = CGRectApplyAffineTransform(rect, transform); newRect.origin = CGPointZero; NSMutableParagraphStyle *textStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy]; textStyle.lineBreakMode = self.lineBreakMode; textStyle.alignment = self.textAlignment; // Apply current label attributes for drawing function. NSDictionary *attributeDict = @{ NSFontAttributeName : self.font, NSForegroundColorAttributeName : self.textColor, NSParagraphStyleAttributeName : textStyle, }; [self.text drawInRect:newRect withAttributes:attributeDict]; } @end


La solución de KoNew en Swift:

extension NSString { func drawWithBasePoint(basePoint:CGPoint, angle:CGFloat, font:UIFont) { var attrs: NSDictionary = [ NSFontAttributeName: font ] var textSize:CGSize = self.sizeWithAttributes(attrs as [NSObject : AnyObject]) // sizeWithAttributes is only effective with single line NSString text // use boundingRectWithSize for multi line text var context: CGContextRef = UIGraphicsGetCurrentContext() var t:CGAffineTransform = CGAffineTransformMakeTranslation(basePoint.x, basePoint.y) var r:CGAffineTransform = CGAffineTransformMakeRotation(angle) CGContextConcatCTM(context, t) CGContextConcatCTM(context, r) self.drawAtPoint(CGPointMake(-1 * textSize.width / 2, -1 * textSize.height / 2), withAttributes: attrs as [NSObject : AnyObject]) CGContextConcatCTM(context, CGAffineTransformInvert(r)) CGContextConcatCTM(context, CGAffineTransformInvert(t)) } }

Usar:

let fieldFont = UIFont(name: "Helvetica Neue", size: 14) myNSString.drawWithBasePoint(CGPointMake(bounds.width/2, bounds.height/2), angle: CGFloat(-M_PI_2), font: fieldFont!)


Resuelvo este problema de la siguiente manera.

1) Declara la categoría en NSString

@interface NSString (NMSchemeItemDraw) -(void) drawWithBasePoint:(CGPoint)basePoint andAngle:(CGFloat)angle andFont:(UIFont*)font; @end

Esta categoría dibujará texto con el punto central dado, en una línea y con la fuente y el ángulo dados.

2) La implementación de esta categoría es como:

@implementation NSString (NMSchemeItemDraw) -(void) drawWithBasePoint:(CGPoint)basePoint andAngle:(CGFloat)angle andFont:(UIFont *)font{ CGSize textSize = [self sizeWithFont:font]; CGContextRef context = UIGraphicsGetCurrentContext(); CGAffineTransform t = CGAffineTransformMakeTranslation(basePoint.x, basePoint.y); CGAffineTransform r = CGAffineTransformMakeRotation(angle); CGContextConcatCTM(context, t); CGContextConcatCTM(context, r); [self drawAtPoint:CGPointMake(-1 * textSize.width / 2, -1 * textSize.height / 2) withFont:font]; CGContextConcatCTM(context, CGAffineTransformInvert(r)); CGContextConcatCTM(context, CGAffineTransformInvert(t)); } @end

3) Ahora puedo usarlo en mi [UIView drawRect:] . Por ejemplo, de la siguiente manera:

-(void)drawRect:(CGRect)rect{ NSString* example = @"Title"; [example drawWithBasePoint:CGPointMake(0.0f, 0.0f) andAngle:M_PI andFont:[UIFont boldSystemFontOfSize:16.0]]; }