วิธีรับข้อความใน CATextLayer ให้ชัดเจน


94

ฉันได้ทำการCALayerเพิ่มCATextLayerและข้อความออกมาพร่ามัว ในเอกสารพวกเขาพูดถึง "การลบรอยหยักแบบพิกเซลย่อย" แต่นั่นไม่ได้มีความหมายกับฉันมากนัก ใครมีข้อมูลโค้ดที่ทำให้CATextLayerมีข้อความที่ชัดเจน

นี่คือข้อความจากเอกสารของ Apple:

หมายเหตุ: CATextLayer ปิดการใช้งานการลบรอยหยักพิกเซลย่อยเมื่อแสดงผลข้อความ สามารถวาดข้อความได้โดยใช้การลบรอยหยักแบบพิกเซลย่อยเท่านั้นเมื่อประกอบเข้ากับพื้นหลังทึบแสงที่มีอยู่ในเวลาเดียวกันกับที่มีการแรสเตอร์ ไม่มีวิธีใดที่จะวาดข้อความลบพิกเซลย่อยด้วยตัวเองไม่ว่าจะเป็นรูปภาพหรือเลเยอร์โดยแยกจากกันก่อนที่จะมีพิกเซลพื้นหลังเพื่อสานพิกเซลข้อความเข้าไป การตั้งค่าคุณสมบัติความทึบของเลเยอร์เป็นใช่จะไม่เปลี่ยนโหมดการแสดงผล

ประโยคที่สองบอกเป็นนัยว่าเราจะได้ข้อความที่ดูดีถ้าcompositesเป็นข้อความexisting opaque background at the same time that it's rasterized. ที่ดี แต่ฉันจะประกอบมันได้อย่างไรและคุณจะให้พื้นหลังทึบแสงได้อย่างไรและคุณจะแรสเตอร์ได้อย่างไร

รหัสที่พวกเขาใช้ในตัวอย่างของเมนูคีออสก์มีดังนี้: (เป็น OS X ไม่ใช่ iOS แต่ฉันคิดว่ามันใช้งานได้!)

NSInteger i;
for (i=0;i<[names count];i++) {
    CATextLayer *menuItemLayer=[CATextLayer layer];
    menuItemLayer.string=[self.names objectAtIndex:i];
    menuItemLayer.font=@"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 

ขอบคุณ!


แก้ไข: การเพิ่มรหัสที่ฉันใช้จริงทำให้ข้อความไม่ชัด มาจากคำถามที่เกี่ยวข้องที่ฉันโพสต์เกี่ยวกับการเพิ่มUILabelแทนที่จะเป็นCATextLayerแต่ได้รับกล่องดำแทน 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);

แก้ไข 2: ดูคำตอบของฉันด้านล่างสำหรับวิธีการแก้ไข sbg.


สิ่งนี้จะไม่ตอบคำถามของคุณ แต่อาจเกี่ยวข้องกับบางคนเช่นฉันที่ต้องการวาดข้อความประกอบเท่านั้นในลักษณะที่คล้ายกับการใช้ UILabel มากที่สุด: stackoverflow.com/questions/3786528/…
DenNukem

คำตอบ:


231

คำตอบสั้น ๆ - คุณต้องตั้งค่ามาตราส่วนเนื้อหา:

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

เมื่อไม่นานมานี้ฉันได้เรียนรู้ว่าเมื่อคุณมีโค้ดการวาดแบบกำหนดเองคุณต้องตรวจสอบการแสดงเรตินาและปรับขนาดกราฟิกของคุณตามนั้น UIKitดูแลส่วนใหญ่รวมถึงการปรับขนาดแบบอักษร

ไม่เป็นเช่นนั้นด้วย CATextLayer.

ความพร่ามัวของฉันมาจากการมี.zPositionที่ไม่ใช่ศูนย์นั่นคือฉันมีการแปลงที่ใช้กับเลเยอร์แม่ของฉัน เมื่อตั้งค่านี้เป็นศูนย์ความพร่ามัวก็หายไปและถูกแทนที่ด้วยพิกเซลที่ร้ายแรง

หลังจากค้นหาสูงและต่ำฉันพบว่าคุณสามารถตั้งค่า.contentsScalea CATextLayerและตั้งค่า[[UIScreen mainScreen] scale]ให้ตรงกับความละเอียดหน้าจอได้ (ฉันคิดว่าสิ่งนี้ใช้ได้กับผู้ที่ไม่ใช่เรตินา แต่ฉันไม่ได้ตรวจ - เหนื่อยเกินไป)

หลังจากรวมสิ่งนี้สำหรับCATextLayerข้อความของฉันก็คมชัด หมายเหตุ - ไม่จำเป็นสำหรับเลเยอร์หลัก

และความพร่าเลือน? มันจะกลับมาเมื่อคุณหมุนในแบบ 3 มิติ แต่คุณไม่สังเกตเห็นเพราะข้อความเริ่มชัดเจนและในขณะที่เคลื่อนไหวคุณไม่สามารถบอกได้

แก้ไขปัญหา!


37
นี่คือคำตอบสั้น ๆtextLayer.contentScale = [[UIScreen mainScreen] scale]; BTW ฉันก็ชอบคำตอบแบบยาวเหมือนกัน :)
nacho4d

สิ่งนี้ใช้กับ CALayer ที่สร้างขึ้นโดยใช้โปรแกรม ตัวอย่างเช่นหากคุณสังเกตเห็นภาพที่วาดลงใน CALayer ของคุณไม่คมชัดบนจอภาพเรตินาอาจเป็นปัญหาและวิธีแก้ไข
Jeff Argast

17
การแก้ไข_textLayer.contentsScale = [[UIScreen mainScreen] scale]; คุณไม่มี "s";)
Ralphleon

1
สิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันเพิ่ม CATextLayer ลงในวิดีโอ (AVFoundation / AVMutableComposition) โดย AVVideoCompositionCoreAnimationTool ข้อความยังคงมีนามแฝง
vietstone

ไม่มีตัวเลือกมาตราส่วนใน mac osx
Sangram Shivankar

36

รวดเร็ว

ตั้งค่าเลเยอร์ข้อความให้ใช้มาตราส่วนเดียวกับหน้าจอ

textLayer.contentsScale = UIScreen.main.scale

ก่อน:

ป้อนคำอธิบายภาพที่นี่

หลังจาก:

ป้อนคำอธิบายภาพที่นี่


macOS swift 4.2 เวอร์ชัน: (NSScreen.main? .backingScaleFactor)!
roberto

16

ก่อนอื่นฉันต้องการชี้ให้เห็นว่าคุณได้แท็กคำถามของคุณด้วย iOS แต่ตัวจัดการข้อ จำกัด มีให้บริการเฉพาะบน OSX ดังนั้นฉันไม่แน่ใจว่าคุณจะทำให้สิ่งนี้ทำงานอย่างไรเว้นแต่คุณจะสามารถเชื่อมโยงกับมันได้ ในโปรแกรมจำลองอย่างใด ในอุปกรณ์ไม่มีฟังก์ชันนี้

ต่อไปฉันจะชี้ให้เห็นว่าฉันสร้าง CATextLayers บ่อยๆและไม่เคยมีปัญหาการเบลอที่คุณอ้างถึงดังนั้นฉันจึงรู้ว่าสามารถทำได้ โดยสรุปการเบลอนี้เกิดขึ้นเนื่องจากคุณไม่ได้วางตำแหน่งเลเยอร์ของคุณบนพิกเซลทั้งหมด จำไว้ว่าเมื่อคุณกำหนดตำแหน่งของเลเยอร์คุณจะใช้ค่าลอยสำหรับ x และ y หากค่าเหล่านั้นมีตัวเลขหลังจุดทศนิยมเลเยอร์จะไม่ถูกวางตำแหน่งบนพิกเซลทั้งหมดและจะให้เอฟเฟกต์การเบลอนี้ซึ่งเป็นระดับที่ขึ้นอยู่กับค่าจริง ในการทดสอบสิ่งนี้เพียงสร้าง CATextLayer และเพิ่มลงในแผนผังเลเยอร์อย่างชัดเจนเพื่อให้แน่ใจว่าพารามิเตอร์ตำแหน่งของคุณอยู่ในพิกเซลทั้งหมด ตัวอย่างเช่น:

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

หากข้อความของคุณยังเบลอแสดงว่ามีบางอย่างผิดปกติ ข้อความเบลอบนเลเยอร์ข้อความของคุณเป็นส่วนหนึ่งของโค้ดที่เขียนไม่ถูกต้องและไม่ใช่ความสามารถที่ตั้งใจไว้ของเลเยอร์ เมื่อเพิ่มเลเยอร์ของคุณไปยังเลเยอร์พาเรนต์คุณสามารถบังคับค่า x และ y กับพิกเซลทั้งหมดที่ใกล้ที่สุดและมันจะช่วยแก้ปัญหาการเบลอของคุณได้


15

ก่อนตั้งค่า shouldRasterize คุณควร:

  1. ตั้งค่า rasterizationScale ของชั้นฐานที่คุณจะแรสเตอร์
  2. ตั้งค่าคุณสมบัติ contentScale ของ CATextLayers ใด ๆ และอาจเป็นเลเยอร์ประเภทอื่น ๆ (ไม่ต้องทำอะไรเลย)

หากคุณไม่ทำ # 1 เลเยอร์ย่อยรุ่นเรติน่าจะดูเบลอแม้กระทั่งสำหรับ CALayers ปกติ

- (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

คุณควรทำ 2 สิ่งอย่างแรกกล่าวไว้ข้างต้น:

ขยาย CATextLayer และตั้งค่าคุณสมบัติทึบแสงและเนื้อหาสเกลเพื่อรองรับการแสดงเรตินาอย่างเหมาะสมจากนั้นแสดงผลโดยเปิดใช้งานการป้องกันนามแฝงสำหรับข้อความ

+ (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];
}

3

หากคุณมาค้นหาที่นี่เพื่อหาปัญหาที่คล้ายกันสำหรับ CATextLayer ใน OSX หลังจากที่หัวผนังกระแทกฉันได้ข้อความที่ชัดเจนโดยทำ:

text_layer.contentsScale = self.window!.backingScaleFactor

(ฉันยังตั้งค่าคอนเทนต์เลเยอร์พื้นหลังของมุมมองให้เหมือนกัน)


0

เร็วขึ้นและง่ายขึ้น: คุณต้องตั้งค่า 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];
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.