2014-03-05 45 views
6

我想在iOS上垂直繪製NSAttributedString(或NSString)。所謂 「垂直」 我的意思是:在iOS上繪製垂直文字

Vertical text example

Apple's documentation說上NSAttributedString標準的屬性是NSVerticalGlyphFormAttributeName,但不幸的是,他說:

「在iOS中,水平文本總是使用與指定不同的值是不確定的。「

The same document還提到NSTextLayoutSectionsAttribute,這似乎支持NSTextLayoutOrientation,它允許NSTextLayoutOrientationHorizontalNSTextLayoutOrientationVertical

這4個術語中沒有一個獲得任何此刻命中SO。 只是那種寂寞的吹哨聲

但是,我不知道如何設置它,無論它是否適用於iOS,或者如果可以用於[myAttributedString drawAtPoint: whereItOughtaGo]風格的垂直字符串渲染。

謝謝。

+0

你想繪製或使用默認的'UILabel'?這可能是'UILabel'.. – Mani

+0

你試過characterwarp – codercat

+0

@iMani我寧願繪製,但我可能能夠使用'UILabel'。 – Benjohn

回答

7

如果它只是一個單行文字,就像在您的示例中一樣,您可以使用各種解決方法。我會親自創建UILabel子如下:

@implementation VerticalLabel 

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super initWithCoder:aDecoder]; 

    if (self) { 
    self.numberOfLines = 0; 
    } 

    return self; 
} 

- (void)setText:(NSString *)text { 
    NSMutableString *newString = [NSMutableString string]; 

    for (int i = text.length-1; i >= 0; i--) { 
    [newString appendFormat:@"%c\n", [text characterAtIndex:i]]; 
    } 

    super.text = newString; 
} 

@end 

現在你只需要更換:

UILabel *lbl = [[UILabel alloc] init]; 

有:

UILabel *lbl = [[VerticalLabel alloc] init]; 

獲得垂直文本。

+1

*點頭*很好的工作,謝謝你。如果我只是想將文本渲染成位圖,我認爲這應該也可以很好地工作。 – Benjohn

+0

完成。在我接受你的答案之前,我會將問題留待一段時間,以便任何人都可以闡明我提到的'NSTextLayoutSectionsAttribute'。 – Benjohn

+0

@Benjohn確保居中文本對齊,以便字母正確對齊(在您的示例中 - '我'在'L'中間等)。 –

5

您可以使用CoreText(獲取字形)和CoreGraphics(繪製CGGlyphs)來繪製垂直文本。 一個簡單的示例,這是隻照顧一個字體屬性(手柄的有效範圍爲每個屬性,如果要處理不同的字體,字體大小等)

#import "NSAttributedString+VerticalDrawing.h" 

@implementation TestView 
- (void)drawRect:(CGRect)rect 
{ 
    NSAttributedString *aString = [[NSAttributedString alloc] initWithString:@"This is a vertical text" 
                    attributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:14.]}]; 
    [aString drawVerticalAtPoint:CGPointMake(10, 10)]; 
} 
@end 

@implementation NSAttributedString (VerticalDrawing) 

- (void)drawVerticalAtPoint:(CGPoint)location 
{ 
    UIFont *font = [[self attributesAtIndex:0 effectiveRange:NULL] objectForKey:NSFontAttributeName]; 
    NSUInteger myLength = [self length]; 

    CTFontRef ctfont = CTFontCreateWithName((CFStringRef)[font fontName], [font pointSize], NULL); 

    CGGlyph *glyphs = malloc(sizeof(CGGlyph) * myLength); 
    UniChar *characters = malloc(sizeof(UniChar) * myLength); 
    CGSize *advances = malloc(sizeof(CGSize) * myLength); 

    [[self string] getCharacters:characters range:NSMakeRange(0,myLength)]; 

    CTFontGetGlyphsForCharacters(ctfont, characters, glyphs, myLength); 
    CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, glyphs, advances, myLength); 

    free(characters); 

    CGContextRef ctx = UIGraphicsGetCurrentContext(); 

    CGFontRef cgfont = CTFontCopyGraphicsFont(ctfont, NULL); 

    CGContextSetFont(ctx, cgfont); 
    CGContextSetFontSize(ctx, CTFontGetSize(ctfont)); 

    CGAffineTransform textMatrix = CGAffineTransformMakeTranslation(location.x, location.y); 
    textMatrix = CGAffineTransformScale(textMatrix, 1, -1); 

    CGContextSetTextMatrix(ctx, textMatrix); 

    CGFloat lineHeight = CTFontGetAscent(ctfont) + CTFontGetDescent(ctfont) + CTFontGetLeading(ctfont); 
    location.y = -CTFontGetAscent(ctfont); 

    CGFloat maxAdvance = 0.; 

    NSUInteger i; 
    for (i = 0; i < myLength; i++) 
     maxAdvance = MAX(maxAdvance, advances[i].width); 

    for (i = 0; i < myLength; i++) 
    { 
     location.x = (maxAdvance - advances[i].width) * 0.5; 

     CGContextShowGlyphsAtPositions(ctx, &glyphs[i], &location, 1); 
     location.y -= lineHeight; 
    } 

    free(glyphs); 
    free(advances); 
    CGFontRelease(cgfont); 
    CFRelease(ctfont); 
} 
@end 

sample

+0

謝謝你的回答@Emmanuel,我不會考慮去那麼低的水平,但它看起來是可以實現的,所以我會重新考慮是否需要。無論我是否使用它,感謝詳細瞭解底層機制如何工作。 – Benjohn

+0

@ Benjohn不客氣。 – Emmanuel

+0

@LeoNatan我編輯了字母居中的代碼 – Emmanuel

1

爲了增加其他很好的答案,我玩NSTextLayoutSectionsAttribute甚至分類NSTextContainer覆蓋layoutOrientation返回NSTextLayoutOrientationVertical。它不起作用。我看到NSATSTypesetter查詢佈局方向,但渲染仍然以水平方向完成。我想這是一個核心文本的限制;文檔和頭文件多次聲明Core文本只支持水平佈局方向。

根據文檔,NSTextLayoutOrientationProvider協議僅在NSLayoutManager的子類希望實現不同的佈局方向時提供。

0

如果您用屬性繪製它,您可以創建一個段落屬性並將左右邊距設置爲0或非常小。這會在使用drawAtPoint時產生一個垂直顯示字符串。