2013-05-03 36 views
4

我有一些CATextLayer的問題,這可能是由於我的原因,但我沒有在這個主題上找到任何幫助。我在OS X上(在iOS上它應該是相同的)。CATextLayer獲取柵格化得太早並且模糊

我創建了一個CATextLayer圖層,比例因子> 1,我得到的是一個模糊的文本。我認爲,在應用比例之前,圖層被光柵化了。這是預期的行爲?我希望它不是,因爲它沒有任何意義...... CAShapeLayer在應用了轉換矩陣之後進行了光柵化處理,爲什麼CATextLayer應該有所不同?

萬一我做錯了什麼事情是什麼?

CATextLayer *layer = [CATextLayer layer]; 
layer.string = @"I like what I am doing"; 
layer.font = (__bridge CFTypeRef)[NSFont systemFontOfSize:24]; 
layer.fontSize = 24; 
layer.anchorPoint = CGPointZero; 
layer.frame = CGRectMake(0, 0, 400, 100); 
layer.foregroundColor = [NSColor blackColor].CGColor; 
layer.transform = CATransform3DMakeScale(2., 2., 1.); 
layer.shouldRasterize = NO; 
[self.layer addSublayer:layer]; 

我現在使用的解決方案是將圖層的contentsScale屬性設置爲比例因子。問題是此解決方案不能縮放:如果任何父層的比例因子發生變化,那麼contentsScale也應該更新。我應該編寫代碼來遍歷圖層樹來更新所有CATextLayers的contentsScale屬性......不完全是我想要做的。

另一個解決方案,這不是一個真正的解決方案,是將文本轉換爲形狀並使用CAShapeLayer。但是,我沒有看到有CATextLayers的意義。

CALayer的自定義子類可以幫助解決這個問題嗎?

編輯:即使CAGradientLayer能夠呈現其內容,如CAShapeLayer,之後,其轉換矩陣應用。有人可以解釋它是如何可能的嗎?

編輯2:我的猜測是路徑和漸變呈現爲OpenGL顯示列表,因此它們通過OpenGL本身在屏幕上的實際大小被柵格化。 Core Animation對文本進行柵格化,因此它們是OpenGL的位圖。

我認爲我現在將用contentScale解決方案。也許,將來我會將文本轉換爲形狀。爲了得到很少的工作最好的結果,這是我現在使用的代碼:

[CATransaction setDisableActions:YES]; 

CGFloat contentsScale = ceilf(scaleOfParentLayer); 
// _scalableTextLayer is a CATextLayer 
_scalableTextLayer.contentsScale = contentsScale; 
[_scalableTextLayer displayIfNeeded]; 

[CATransaction setDisableActions:NO]; 

回答

1

嘗試所有方法後,我現在使用的解決方案是CALayer的自定義子類。我根本不使用CATextLayer。

我與此自定義setter方法重寫contentsScale屬性:

- (void)setContentsScale:(CGFloat)cs 
{ 
    CGFloat scale = MAX(ceilf(cs), 1.); // never less than 1, always integer 
    if (scale != self.contentsScale) { 
     [super setContentsScale:scale]; 
     [self setNeedsDisplay]; 
    } 
} 

的屬性的值總是舍入到上的整數值。當四捨五入的值改變時,圖層必須重畫。

我的CALayer子類的顯示方法創建一個文本大小乘以contentsScale因子和屏幕比例因子的位圖圖像。

- (void)display 
{ 
    CGFloat scale = self.contentsScale * [MyUtils screenScale]; 

    CGFloat width = self.bounds.size.width * scale; 
    CGFloat height = self.bounds.size.height * scale; 

    CGContextRef bitmapContext = [MyUtils createBitmapContextWithSize:CGSizeMake(width, height)]; 

    CGContextScaleCTM(bitmapContext, scale, scale); 
    CGContextSetShouldSmoothFonts(bitmapContext, 0); 

    CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)(_text)); 

    CGContextSetTextPosition(bitmapContext, 0., self.bounds.size.height-_ascender); 
    CTLineDraw(line, bitmapContext); 
    CFRelease(line); 

    CGImageRef image = CGBitmapContextCreateImage(bitmapContext); 
    self.contents = (__bridge id)(image); 
    CGImageRelease(image); 

    CGContextRelease(bitmapContext); 
} 

當我改變我的層次結構的根層的比例因子,我所有的文字圖層環路和contentsScale屬性設置爲相同的因素。只有當比例因子的四捨五入值發生變化時纔會調用顯示方法(即如果前一個值爲1.6,現在我設置爲1.7,則不會發生任何變化,但如果新值爲2.1,則會重新顯示該圖層)。

重繪速度方面的成本很小。我的測試是連續改變第三代40層文字層次的比例因子。 iPad兼容。它的作用像黃油。

0

CATextLayer是不同的,因爲底層的CoreText呈現與指定的字體大小(基於實驗的猜測)的字形。

您可以將動作添加到父圖層,以便在縮放更改後立即更改文字圖層的字體大小。

模糊也可能來自未對齊的像素。如果您將文本圖層置於非整數位置或超級層次結構中的任何轉換,就會發生這種情況。

或者你可以繼承CALayer的,然後在drawInContext使用可可繪製文本: 看到這裏的例子: http://lists.apple.com/archives/Cocoa-dev/2009/Jan/msg02300.html http://people.omnigroup.com/bungi/TextDrawing-20090129.zip

+0

嗨瑪哈爾,謝謝你的回覆。當父圖層的縮放比例發生變化時,我無法更改字體大小:文本大小將乘以父級的縮放比例因子,而較大的字體大小沒有任何好處。我會得到一個更大,更模糊的文字。 – mbt 2013-05-06 15:04:25

+0

它工作?然後,您可以添加更多詳細信息並將問題標記爲已回答。 – 2013-11-11 17:18:30

0

如果你想有一個CAShapeLayer的具體行爲,那麼你將需要轉換您的字符串轉換成bezier路徑,並使CAShapeLayer呈現它。這是一個工作,但你會有你正在尋找的確切行爲。另一種方法是改變fontSize的大小。這樣每次都會產生清晰的文字,但它可能不適合您的確切情況。

+0

嗨「級別」,問題是我需要爲父級設置比例因子,所以我無法更改字體大小。 – mbt 2013-05-06 15:05:53