2012-04-23 35 views
16

Tôi tìm thấy câu trả lời này về cách vẽ chữ xoay với NSString drawInRect :, nhưng tôi không chắc làm thế nào nó hoạt động vì nó chỉ loại làm việc cho tôi: https://discussions.apple.com/thread/1779814?start=0&tstart=0Vẽ xoay văn bản với NSString drawInRect

mã trông My như:

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

Vì vậy, khi tôi sử dụng điều này, tôi thấy văn bản được vẽ 45 độ bên dưới trục x. Tôi muốn vẽ văn bản theo chiều dọc dọc theo lineargradient của tôi. Vì vậy, tôi nghĩ rằng tôi có thể làm điều đó bằng cách sử dụng M_PI/2 cho 90 độ. Tôi không thấy văn bản của tôi mặc dù. Tôi đã thử các biến đổi khác nhau cho phép quay và chỉ một số có vẻ hoạt động như M_PI/4 và M_PI/8. Tôi sẽ nghĩ rằng nếu tôi sử dụng -M_PI/4 nó sẽ có văn bản 45 độ trên trục x và M_PI/2 sẽ là 90 độ bên dưới trục x. Nhưng cả hai đều không có gì cả.

Mọi suy nghĩ? cảm ơn.

Trả lời

12

Tôi nghĩ điều đang xảy ra là bạn đang xoay văn bản đến một vị trí bên ngoài chế độ xem vì nó xoay ngữ cảnh bằng cách xoay vòng trên nguồn gốc.

Sau khi xoay, bạn cần thực hiện một bản dịch để chuyển ngữ cảnh trở lại chế độ xem. Trong ví dụ dưới đây, tôi xoay ngữ cảnh ngược chiều kim đồng hồ 90 độ. Sau đó, tôi dịch tx của bối cảnh khoảng cách của chiều cao.

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

Lưu ý rằng bạn cũng có thể nhận được kích thước chuỗi sẽ được hiển thị, có thể giúp tính toán căn chỉnh văn bản.

CGSize stringSize = [string sizeWithFont:font]; 
+0

Cảm ơn rất nhiều. nhưng nếu tôi thay đổi -M_PI_2 thành M_PI_2. chuỗi này sẽ biến mất. TẠI SAO? – Jacky

+1

Tôi nhận được nó, nếu thay đổi -M_PI_2 thành M_PI_2, nó cũng cần phải thay đổi CGContextTranslateCTM (ngữ cảnh, -rect.size.height, 0); tới CGContextTranslateCTM (ngữ cảnh, 0, -rect.size.height); – Jacky

15

Tôi giải quyết vấn đề này theo cách tiếp theo.

1) Khai báo loại trên NSString

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

Thể loại này sẽ rút ra văn bản với cho điểm trung tâm, trong một dòng và với font chữ nhất định và góc.

2) Thực hiện của thể loại này là hình như:

@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) Bây giờ tôi có thể sử dụng nó trong phương pháp [UIView drawRect:] tôi. Ví dụ, trong một cách tiếp theo:

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

Giải pháp tốt đẹp ... Dễ dàng hơn nhiều để vượt qua trong một vài tham số và để cho hàm xử lý mọi thứ khác – jsetting32

+0

Rất thanh lịch! sizeWithFont và drawAtPoint: withFont hiện không còn được dùng nữa. Thay thế dòng mã CGSize textSize ... của bạn bằng mã này: NSDictionary * attributes = @ {NSFontAttributeName: specifiedFont}; CGSize textSize = [tự sizeWithAttributes: thuộc tính]; hoạt động như được quảng cáo. Lệnh gọi phương thức drawAtPoint cũng cần được cập nhật. Chỉ cần thay thế 'withFont: font' bằng 'withAttributes: attributes'. Cảm ơn một lần nữa cho giải pháp sạch này. – Scooter

+0

Câu trả lời thú vị !!! –

5

Giải pháp KoNew trong 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)) 


    } 


} 

Cách sử dụng:

let fieldFont = UIFont(name: "Helvetica Neue", size: 14) 

myNSString.drawWithBasePoint(CGPointMake(bounds.width/2, bounds.height/2), angle: CGFloat(-M_PI_2), font: fieldFont!) 
0

Thank cho bài viết này, và Chris's answer, và Arkadiusz's answer at another post.

Cuối cùng, tôi giải quyết vấn đề này bằng lớp con UILabel, có tên là MyVerticalLabel và làm cho nó vẽ văn bản dọc.

@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 
5

Đây là phiên bản cập nhật và đơn giản hóa câu trả lời của KoNEW. Nó bảo toàn trạng thái của bối cảnh đồ họa như một phần thưởng. Đây cũng là một hàm đơn giản thay vì một phần mở rộng 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() 
} 
Các vấn đề liên quan