2010-09-28 10 views
78

Zrobiłem CALayer z dodanym CATextLayer i tekst jest rozmazany. W dokumentach mówią o "antyaliasingu subpikselowym", ale to niewiele dla mnie znaczy. Ktoś ma fragment kodu, który sprawia, że ​​CATextLayer z jasnym tekstem?Jak uzyskać tekst w tekście CATextLayer, aby było jasne

Oto tekst z dokumentacji Apple:

Uwaga: CATextLayer wyłącza subpiksel antyaliasing podczas renderowania tekstu. Tekst można narysować tylko za pomocą subumikselowego wygładzania krawędzi, gdy jest on wkomponowany w istniejące nieprzezroczyste tło w tym samym czasie, co , zrasteryzowany. Nie ma możliwości samodzielnego narysowania tekstu z podpowiedziami podrzędnymi, niezależnie od tego, czy jest to obraz, czy warstwa, oddzielnie przed z pikselami tła, na których tkane są piksele tekstowe. Ustawienie właściwości nieprzezroczystości warstwy na TAK nie zmienia trybu renderowania .

Drugie zdanie sugeruje, że można uzyskać dobre patrząc tekst jeśli jeden composites go w existing opaque background at the same time that it's rasterized. to świetnie, ale jak mam kompozyt jest i jak można dać nieprzezroczystego tła i jak można go rasteryzację?

Kod używają ich przykładzie kiosku Menu jest w następujący sposób: (to OS X, a nie na iOS, ale zakładam, że to działa!)

NSInteger i; 
for (i=0;i<[names count];i++) { 
    CATextLayer *menuItemLayer=[CATextLayer layer]; 
    menuItemLayer.string=[self.names objectAtIndex:i]; 
    [email protected]"Lucida-Grande"; 
    menuItemLayer.fontSize=fontSize; 
    menuItemLayer.foregroundColor=whiteColor; 
    [menuItemLayer addConstraint:[CAConstraint 
     constraintWithAttribute:kCAConstraintMaxY 
         relativeTo:@"superlayer" 
         attribute:kCAConstraintMaxY 
          offset:-(i*height+spacing+initialOffset)]]; 
    [menuItemLayer addConstraint:[CAConstraint 
     constraintWithAttribute:kCAConstraintMidX 
         relativeTo:@"superlayer" 
         attribute:kCAConstraintMidX]]; 
    [self.menuLayer addSublayer:menuItemLayer]; 
} // end of for loop 

Dzięki!


EDYCJA: Dodanie kodu, którego faktycznie użyłem, spowodowało rozmycie tekstu. To z pokrewnego pytania, które napisałem o dodaniu UILabel zamiast CATextLayer, ale zamiast tego otrzymam czarne pudełko. http://stackoverflow.com/questions/3818676/adding-a-uilabels-layer-to-a-calayer-and-it-just-shows-black-box

CATextLayer* upperOperator = [[CATextLayer alloc] init]; 
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 
CGFloat components1[4] = {1.0, 1.0, 1.0, 1.0}; 
CGColorRef almostWhite = CGColorCreate(space,components1); 
CGFloat components2[4] = {0.0, 0.0, 0.0, 1.0}; 
CGColorRef almostBlack = CGColorCreate(space,components2); 
CGColorSpaceRelease(space); 
upperOperator.string = [NSString stringWithFormat:@"13"]; 
upperOperator.bounds = CGRectMake(0, 0, 100, 50); 
upperOperator.foregroundColor = almostBlack; 
upperOperator.backgroundColor = almostWhite; 
upperOperator.position = CGPointMake(50.0, 25.0); 
upperOperator.font = @"Helvetica-Bold"; 
upperOperator.fontSize = 48.0f; 
upperOperator.borderColor = [UIColor redColor].CGColor; 
upperOperator.borderWidth = 1; 
upperOperator.alignmentMode = kCAAlignmentCenter; 
[card addSublayer:upperOperator]; 
[upperOperator release]; 
CGColorRelease(almostWhite); 
CGColorRelease(almostBlack); 

EDIT 2: Zobacz moją odpowiedź poniżej dla mnie jak to rozwiązać. sbg.

+0

To nie odpowie na to pytanie, ale może być istotne dla kogoś takiego jak ja, kto szuka tylko wyciągnąć nadana tekst, w sposób najbardziej podobny do używania UILabel: http://stackoverflow.com/questions/3786528/iphone-ipad-how-exactly-use-nsattributedstrin g – DenNukem

Odpowiedz

190

Krótka odpowiedź - trzeba ustawić zawartość skalowania:

textLayer.contentsScale = [[UIScreen mainScreen] scale]; 

Jakiś czas temu dowiedziałem się, że gdy masz zwyczaj rysowania kod, trzeba sprawdzić na wyświetlaczu siatkówki i skalowanie grafiki odpowiednio. UIKit zajmuje się większością tego, w tym skalowaniem czcionek.

Nie tak z CATextLayer.

Moja zamazany przyszedł z posiadania .zPosition że nie było zero, to znaczy, miałem transformacji zastosowane do mojego warstwy nadrzędnej. Ustawiając tę ​​wartość na zero, rozmazanie zniknęło i zostało zastąpione przez poważną pikselację.

Po wyszukaniu wysokiego i niskiego poziomu, stwierdziłem, że można ustawić .contentsScale dla CATextLayer i można ustawić go na [[UIScreen mainScreen] scale], aby dopasować rozdzielczość ekranu. (Zakładam, że działa to dla nie-siatkówki, ale nie sprawdziłem - zbyt zmęczony)

Po włączeniu tego do mojego CATextLayer tekst stał się wyraźny. Uwaga - nie jest to konieczne dla warstwy nadrzędnej.

A rozmazanie? Wraca, gdy obracasz się w 3D, ale nie zauważysz tego, ponieważ tekst zaczyna się wyraźnie i gdy jest w ruchu, nie możesz tego powiedzieć.

Problem rozwiązany!

+37

To jest krótka odpowiedź: 'textLayer.contentScale = [[UIScreen mainScreen] scale];' BTW, lubię długie odpowiedzi też :) – nacho4d

+0

Dotyczy to każdej CALayer, która jest tworzona programowo. Na przykład, jeśli zauważysz, że obrazy wciągnięte na twój CALayer nie są wyraźne na ekranie siatkówki, prawdopodobnie jest to problem i rozwiązanie. –

+17

Korekta '_textLayer.contentsScale = [[UIScreen mainScreen] skala];" Brakuje "s";) – Ralphleon

17

Po pierwsze, chciałem podkreślić, że otagowałeś swoje pytanie w iOS, ale menedżerowie ograniczeń są dostępne tylko w systemie OSX, więc nie jestem pewien, jak to działa, chyba że jesteś w stanie jakoś połączyć się z nim w symulatorze. Na urządzeniu ta funkcja nie jest dostępna.

Następnie, po prostu zwrócę uwagę, że często tworzę CATextLayers i nigdy nie mam problemu z rozmyciem, o którym mówisz, więc wiem, że można to zrobić. W dużym skrócie to rozmycie występuje, ponieważ nie umieszczasz swojej warstwy na całym pikselu. Pamiętaj, że ustawiając pozycję warstwy, używasz wartości zmiennoprzecinkowych dla x i y. Jeśli te wartości mają liczby po przecinku, warstwa nie zostanie umieszczona na całym pikselu i dlatego da efekt rozmycia - którego stopień zależy od rzeczywistych wartości. Aby to przetestować, po prostu utwórz CATextLayer i jawnie dodaj go do drzewa warstw, upewniając się, że twój parametr pozycji jest na całym pikselu. Na przykład:

CATextLayer *textLayer = [CATextLayer layer]; 
[textLayer setBounds:CGRectMake(0.0f, 0.0f, 200.0f, 30.0f)]; 
[textLayer setPosition:CGPointMake(200.0f, 100.0f)]; 
[textLayer setString:@"Hello World!"]; 

[[self menuLayer] addSublayer:textLayer]; 

Jeśli tekst jest nadal niewyraźny, oznacza to, że coś jest nie tak. Niewyraźny tekst na warstwie tekstowej jest artefaktem niepoprawnie napisanego kodu, a nie zamierzoną zdolnością warstwy.Dodając swoje warstwy do warstwy nadrzędnej, możesz po prostu zmusić wartości xiy do najbliższego całego piksela i powinno to rozwiązać problem z rozmyciem.

12

Przed ustawieniem shouldRasterize, należy:

  1. ustawić rasterizationScale warstwy bazowej idziesz do rasteryzację
  2. ustawić właściwość contentsScale wszelkich CATextLayers i ewentualnie innych rodzajów warstw (nigdy nie boli zrób to)

Jeśli nie zrobisz 1, wtedy wersja pod-warstwowa będzie wyglądać na zamgloną, nawet dla zwykłych CALayerów.

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    CALayer *mainLayer = [[self view] layer]; 
    [mainLayer setRasterizationScale:[[UIScreen mainScreen] scale]]; 

    CATextLayer *messageLayer = [CATextLayer layer]; 
    [messageLayer setForegroundColor:[[UIColor blackColor] CGColor]]; 
    [messageLayer setContentsScale:[[UIScreen mainScreen] scale]]; 
    [messageLayer setFrame:CGRectMake(50, 170, 250, 50)]; 
    [messageLayer setString:(id)@"asdfasd"]; 

    [mainLayer addSublayer:messageLayer]; 

    [mainLayer setShouldRasterize:YES]; 
} 
4

należy zrobić 2 rzeczy, pierwszy wspomniano powyżej:

Extend CATextLayer i ustawić właściwości kryjących i contentsScale prawidłowo obsługiwać wyświetlacz Retina, a następnie uczynić z anty aliasing włączona do tekstu.

+ (TextActionLayer*) layer 
{ 
    TextActionLayer *layer = [[TextActionLayer alloc] init]; 
    layer.opaque = TRUE; 
    CGFloat scale = [[UIScreen mainScreen] scale]; 
    layer.contentsScale = scale; 
    return [layer autorelease]; 
} 

// Render after enabling with anti aliasing for text 

- (void)drawInContext:(CGContextRef)ctx 
{ 
    CGRect bounds = self.bounds; 
    CGContextSetFillColorWithColor(ctx, self.backgroundColor); 
    CGContextFillRect(ctx, bounds); 
    CGContextSetShouldSmoothFonts(ctx, TRUE); 
    [super drawInContext:ctx]; 
} 
0

Jeśli przyszedł szukając tutaj podobnego problemu na CATextLayer w OSX, po wielu głowy ściana walenie, mam ostry wyraźny tekst, wykonując:

text_layer.contentsScale = self.window!.backingScaleFactor 

(ja również ustawić punkt widzenia zawartość warstwy tła Skala być taka sama).

0

To jest szybsze i łatwiejsze: wystarczy ustawić contentsScale

CATextLayer *label = [[CATextLayer alloc] init]; 
    [label setFontSize:15]; 
    [label setContentsScale:[[UIScreen mainScreen] scale]]; 
    [label setFrame:CGRectMake(0, 0, 50, 50)]; 
    [label setString:@"test"]; 
    [label setAlignmentMode:kCAAlignmentCenter]; 
    [label setBackgroundColor:[[UIColor clearColor] CGColor]]; 
    [label setForegroundColor:[[UIColor blackColor] CGColor]]; 
    [self addSublayer:label]; 
14

Swift

Ustaw warstwę tekstową, aby korzystać z tej samej skali, jak na ekranie.

textLayer.contentsScale = UIScreen.main.scale 

Przed:

enter image description here

Po:

enter image description here

Powiązane problemy