2012-01-04 13 views
11

मैं एक पारदर्शी लेबल के रूप में एक UILabel (उपclassing के माध्यम से बेहतर) आकर्षित करने के लिए देख रहा हूँ, लेकिन ठोस पृष्ठभूमि के साथ। मैं एक त्वरित उदाहरण खींचता हूं (क्षमा करें, यह बदसूरत है, लेकिन यह अंक भर जाता है :))।drawRect ड्राइंग 'पारदर्शी' पाठ?

मूल रूप से मेरे पास एक UILabel है और मैं पृष्ठभूमि को एक सेट रंग होना चाहता हूं, और पाठ पारदर्शी होना चाहिए। मैं दृश्य पृष्ठभूमि के साथ पाठ को रंगना नहीं चाहता हूं, लेकिन इसके बजाय यह 100% पारदर्शी है, क्योंकि मेरे पास पृष्ठभूमि में एक बनावट है जिसे मैं लेबल के अंदर और बाहर लाइनों को सुनिश्चित करना चाहता हूं।

मैं रात्रि ब्राउज़िंग SO और Google पर खोज कर रहा हूं, लेकिन मुझे कोई उपयोगी स्रोत नहीं मिला है। मुझे सीजी ड्राइंग के साथ ज्यादा अनुभव नहीं है, इसलिए मैं किसी भी लिंक, सहायता, ट्यूटोरियल या नमूना कोड की सराहना करता हूं (शायद ऐप्पल में मुझे कुछ देखने की ज़रूरत है?)।

धन्यवाद एक गुच्छा!

enter image description here

+0

अब तक, आगे रोमांचक क्वार्ट्ज दस्तावेज़ों में गोताखोरी से, मेरा मानना ​​है कि मैं 'CGContextSetTextDrawingMode' और' kCGTextClip' – runmad

+0

उपयोग करने के लिए http://stackoverflow.com/questions/19787238/transparent- को मेरा उत्तर देखें जरूरत इस समस्या के पथ-आधारित दृष्टिकोण के लिए uilabel-textcolor-on-superview-superview-sort-of। –

उत्तर

12

मैं मुश्किल से किसी भी कोड का उपयोग कर एक UILabel उपवर्ग के रूप में यह फिर से लिखा और GitHub

यह का सार आप drawRect ओवरराइड लेकिन फोन [super drawRect:rect] UILabel सामान्य रूप में प्रस्तुत करना यह बताने के लिए है पर यह पोस्ट किया है। एक सफेद लेबल रंग का उपयोग करने से आप आसानी से लेबल को मास्क के रूप में उपयोग कर सकते हैं।

- (void)drawRect:(CGRect)rect 
{ 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // let the superclass draw the label normally 
    [super drawRect:rect]; 

    CGContextConcatCTM(context, CGAffineTransformMake(1, 0, 0, -1, 0, CGRectGetHeight(rect))); 

    // create a mask from the normally rendered text 
    CGImageRef image = CGBitmapContextCreateImage(context); 
    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerComponent(image), CGImageGetBitsPerPixel(image), CGImageGetBytesPerRow(image), CGImageGetDataProvider(image), CGImageGetDecode(image), CGImageGetShouldInterpolate(image)); 

    CFRelease(image); image = NULL; 

    // wipe the slate clean 
    CGContextClearRect(context, rect); 

    CGContextSaveGState(context); 
    CGContextClipToMask(context, rect, mask); 

    CFRelease(mask); mask = NULL; 

    [self RS_drawBackgroundInRect:rect]; 

    CGContextRestoreGState(context); 

} 
4

CALayer मास्क का उपयोग कर हल। एक मानक मुखौटा बनाना (उदाहरण के लिए दीवार के टुकड़े वाले पाठ) सरल है। नॉक-आउट टेक्स्ट बनाने के लिए, मुझे अपने मास्क के अल्फा चैनल को उलटा करना पड़ा, जिसमें एक CGImageRef को लेबल प्रस्तुत करना और फिर कुछ पिक्सेल-पुशिंग करना शामिल था।

sample mask

नमूना आवेदन यहाँ उपलब्ध है:

#import "RSMaskedLabel.h" 
#import <QuartzCore/QuartzCore.h> 

@interface UIImage (RSAdditions) 
+ (UIImage *) imageWithView:(UIView *)view; 
- (UIImage *) invertAlpha; 
@end 

@interface RSMaskedLabel() 
{ 
    CGImageRef invertedAlphaImage; 
} 
@property (nonatomic, retain) UILabel *knockoutLabel; 
@property (nonatomic, retain) CALayer *textLayer; 
- (void) RS_commonInit; 
@end 

@implementation RSMaskedLabel 
@synthesize knockoutLabel, textLayer; 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) 
    { 
     [self RS_commonInit]; 
    } 
    return self; 
} 

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

+ (Class)layerClass 
{ 
    return [CAGradientLayer class]; 
} 

- (void) RS_commonInit 
{ 
    [self setBackgroundColor:[UIColor clearColor]]; 

    // create the UILabel for the text 
    knockoutLabel = [[UILabel alloc] initWithFrame:[self frame]]; 
    [knockoutLabel setText:@"booyah"]; 
    [knockoutLabel setTextAlignment:UITextAlignmentCenter]; 
    [knockoutLabel setFont:[UIFont boldSystemFontOfSize:72.0]]; 
    [knockoutLabel setNumberOfLines:1]; 
    [knockoutLabel setBackgroundColor:[UIColor clearColor]]; 
    [knockoutLabel setTextColor:[UIColor whiteColor]]; 

    // create our filled area (in this case a gradient) 
    NSArray *colors = [[NSArray arrayWithObjects: 
         (id)[[UIColor colorWithRed:0.349 green:0.365 blue:0.376 alpha:1.000] CGColor], 
         (id)[[UIColor colorWithRed:0.455 green:0.490 blue:0.518 alpha:1.000] CGColor], 
         (id)[[UIColor colorWithRed:0.412 green:0.427 blue:0.439 alpha:1.000] CGColor], 
         (id)[[UIColor colorWithRed:0.208 green:0.224 blue:0.235 alpha:1.000] CGColor], 
         nil] retain]; 

    NSArray *gradientLocations = [NSArray arrayWithObjects: 
            [NSNumber numberWithFloat:0.0], 
            [NSNumber numberWithFloat:0.54], 
            [NSNumber numberWithFloat:0.55], 
            [NSNumber numberWithFloat:1], nil]; 

    // render our label to a UIImage 
    // if you remove the call to invertAlpha it will mask the text 
    invertedAlphaImage = [[[UIImage imageWithView:knockoutLabel] invertAlpha] CGImage]; 

    // create a new CALayer to use as the mask 
    textLayer = [CALayer layer]; 
    // stick the image in the layer 
    [textLayer setContents:(id)invertedAlphaImage]; 

    // create a nice gradient layer to use as our fill 
    CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer]; 

    [gradientLayer setBackgroundColor:[[UIColor clearColor] CGColor]]; 
    [gradientLayer setColors: colors]; 
    [gradientLayer setLocations:gradientLocations]; 
    [gradientLayer setStartPoint:CGPointMake(0.0, 0.0)]; 
    [gradientLayer setEndPoint:CGPointMake(0.0, 1.0)]; 
    [gradientLayer setCornerRadius:10]; 

    // mask the text layer onto our gradient 
    [gradientLayer setMask:textLayer]; 
} 

- (void)layoutSubviews 
{ 
    // resize the text layer 
    [textLayer setFrame:[self bounds]]; 
} 

- (void)dealloc 
{ 
    CGImageRelease(invertedAlphaImage); 
    [knockoutLabel release]; 
    [textLayer  release]; 
    [super   dealloc]; 
} 

@end 

@implementation UIImage (RSAdditions) 

/* 
create a UIImage from a UIView 
*/ 
+ (UIImage *) imageWithView:(UIView *)view 
{ 
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0.0); 
    [view.layer renderInContext:UIGraphicsGetCurrentContext()]; 

    UIImage * img = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    return img; 
} 

/* 
get the image to invert its alpha channel 
*/ 
- (UIImage *)invertAlpha 
{ 
    // scale is needed for retina devices 
    CGFloat scale = [self scale]; 
    CGSize size = self.size; 
    int width = size.width * scale; 
    int height = size.height * scale; 

    CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); 

    unsigned char *memoryPool = (unsigned char *)calloc(width*height*4, 1); 

    CGContextRef context = CGBitmapContextCreate(memoryPool, width, height, 8, width * 4, colourSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast); 

    CGColorSpaceRelease(colourSpace); 

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]); 

    for(int y = 0; y < height; y++) 
    { 
     unsigned char *linePointer = &memoryPool[y * width * 4]; 

     for(int x = 0; x < width; x++) 
     { 
      linePointer[3] = 255-linePointer[3]; 
      linePointer += 4; 
     } 
    } 

    // get a CG image from the context, wrap that into a 
    CGImageRef cgImage = CGBitmapContextCreateImage(context); 
    UIImage *returnImage = [UIImage imageWithCGImage:cgImage scale:scale orientation:UIImageOrientationUp]; 

    // clean up 
    CGImageRelease(cgImage); 
    CGContextRelease(context); 
    free(memoryPool); 

    // and return 
    return returnImage; 
} 
@end 
4

यहाँ एक तकनीक मैट Gallagher के लिए इसी तरह की है कि, जो उत्पन्न होगा है: https://github.com/robinsenior/RSMaskedLabel

प्रासंगिक कोड भविष्य लिंक-सड़ांध से बचने के लिए यहाँ है एक छवि के साथ एक उलटा पाठ मुखौटा।

एक (परिवर्तनीय) डेटा बफर आवंटित करें। 8-बिट अल्फा चैनल के साथ बिटमैप संदर्भ बनाएं। टेक्स्ट ड्राइंग के लिए सेटिंग्स कॉन्फ़िगर करें। प्रतिलिपि में पूर्ण बफर भरें (डिफ़ॉल्ट रंग माना जाता है कि 1 का अल्फा मान है)। स्पष्ट मोड में टेक्स्ट लिखें (0 का अल्फा मान)। बिटमैप संदर्भ से एक छवि बनाएँ। स्रोत छवि से एक नई छवि बनाने के लिए एक मुखौटा के रूप में बिटमैप का उपयोग करें। एक नया UIImage बनाएँ और साफ करें।

हर बार टेक्स्टस्ट्रिंग या स्रोत छवि या आकार मान बदलते हैं, अंतिम छवि को पुन: उत्पन्न करते हैं।

CGSize size = /* assume this exists */; 
UIImage *sourceImage = /* assume this exists */; 
NSString *textString = /* assume this exists */; 
char *text = [textString cStringUsingEncoding:NSMacOSRomanStringEncoding]; 
NSUInteger len = [textString lengthOfBytesUsingEncoding:cStringUsingEncoding:NSMacOSRomanStringEncoding]; 

NSMutableData *data = [NSMutableData dataWithLength:size.width*size.height*1]; 
CGContextRef context = CGBitmapContextCreate([data mutableBytes], size.width, size.height, 8, size.width, NULL, kCGImageAlphaOnly); 

CGContextSelectFont(context, "Gill Sans Bold", 64.0f, kCGEncodingMacRoman); 
CGContextSetTextDrawingMode(context, kCGTextFill); 

CGContextSetBlendMode(context, kCGBlendModeCopy); 
CGContextFillRect(context, overlay.bounds); 
CGContextSetBlendMode(context, kCGBlendModeClear); 
CGContextShowTextAtPoint(context, 16.0f, 16.0f, text, len); 

CGImageRef textImage = CGBitmapContextCreateImage(context); 
CGImageRef newImage = CGImageCreateWithMask(sourceImage.CGImage, textImage); 

UIImage *finalImage = [UIImage imageWithCGImage:newImage]; 

CGContextRelease(context); 
CFRelease(newImage); 
CFRelease(textImage); 

ऐसा करने का एक और तरीका टेक्स्ट इमेज को एक नई परत में डालने और उस परत को आपके दृश्य की परत पर सेट करना शामिल है। (लाइनों है कि बनाने के "newImage" और "finalImage" निकालें।) यह मानते हुए कहीं अपने दृश्य के कोड के अंदर होता है:

CALayer *maskLayer = [[CALayer alloc] init]; 
CGPoint position = CGPointZero; 

// layout the new layer 
position = overlay.layer.position; 
position.y *= 0.5f; 
maskLayer.bounds = overlay.layer.bounds; 
maskLayer.position = position; 
maskLayer.contents = (__bridge id)textImage; 

self.layer.mask = maskLayer; 

अधिक विकल्प नहीं हैं, कुछ बेहतर (उपवर्ग UIImage हो सकता है और स्पष्ट में सीधे पाठ आकर्षित हो सकता है सुपरक्लास ने अपना ड्राइंग करने के बाद मोड?)।

+0

रॉबिन सीनियर का नया जवाब अब सबसे अच्छा जवाब है! –

संबंधित मुद्दे