Search code examples
cocoa-touchcore-graphicsquartz-graphics

Cocoa Touch - Adding texture with overlay view


I have a set of tiles as UIViews that have a programmable background color, and each one can be a different color. I want to add texture, like a side-lit bevel, to each one. Can this be done with an overlay view or by some other method?

I'm looking for suggestions that don't require a custom image file for each case.


Solution

  • This may help someone, although this was pieced together from other topics on SO. To create a beveled tile image with an arbitrary color for normal and for retina display, I made a beveled image in photoshop and set the saturation to zero, making a grayscale image called tileBevel.png

    tileBevel.png

    I also created one for the retina display ([email protected])

    Here is the code:

    + (UIImage*) createTileWithColor:(UIColor*)tileColor {
    
        int pixelsHigh = 44;
        int pixelsWide = 46;
        UIImage *bottomImage;
    
        if([UIScreen respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.0) {
            pixelsHigh *= 2;
            pixelsWide *= 2;
            bottomImage = [UIImage imageNamed:@"[email protected]"];        
        }
        else {
            bottomImage = [UIImage imageNamed:@"tileBevel.png"];
        }
    
        CGImageRef theCGImage = NULL;
        CGContextRef tileBitmapContext = NULL;
    
        CGRect rectangle = CGRectMake(0,0,pixelsWide,pixelsHigh);
    
        UIGraphicsBeginImageContext(rectangle.size);
    
        [bottomImage drawInRect:rectangle];
    
        tileBitmapContext = UIGraphicsGetCurrentContext();
    
        CGContextSetBlendMode(tileBitmapContext, kCGBlendModeOverlay);
    
        CGContextSetFillColorWithColor(tileBitmapContext, tileColor.CGColor);        
        CGContextFillRect(tileBitmapContext, rectangle);
    
        theCGImage=CGBitmapContextCreateImage(tileBitmapContext);
    
        UIGraphicsEndImageContext();
    
        return [UIImage imageWithCGImage:theCGImage];
    
    }
    

    This checks to see if the retina display is used, sizes the rectangle to draw in, picks the appropriate grayscale base image, set the blending mode to overlay, then draws a rectangle on top of the bottom image. All of this is done inside a graphics context bracketed by the BeginImageContext and EndImageContext calls. These set the current context needed by the UIImage drawRect: method. The Core Graphics functions need the context as a parameter, which is obtained by a call to get the current context.

    And the result looks like this:

    enter image description here