8

I want to be able to an UI object like a UIImageView and tile an image inside of it.

I have been able to use CGContextDrawTiledImage to update the background in the main window, but not an image view. I can do this if I modify the drawRect function inside the MainView class.

I feel I'm close, but still missing something. Can someone point me in the right direction?

- (void)drawRect:(CGRect)rect {

CGImageRef image = CGImageRetain(currentImage.CGImage);

CGRect imageRect;
imageRect.origin = CGPointMake(160, 240);
imageRect.size = CGSizeMake(320.0, 480.0);

CGContextRef uiContext = UIGraphicsGetCurrentContext();

CGContextClipToRect(uiContext, CGRectMake(0.0, 0.0, rect.size.width, rect.size.height));

CGContextDrawTiledImage(uiContext, imageRect, image);

}

Chris Craft
  • 5,285
  • 6
  • 46
  • 63
  • 1
    This is very old question, i know: just in case anyone stumbles here: you shouldn't override drawRect of UIImageView - i think it's the only UIView subclass in UIKit with this restriction... – Rok Jarc Jan 18 '13 at 22:24

5 Answers5

26

If you just want to tile an image in the view, change it to a normal UIView and tile the background with UIColor initWithPatternImage:

backgroundView.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageWithContentsOfFile:[self bundlePath:@"some_tile_image.png" inDirectory:@"tiles"]]];
Chris Blackwell
  • 9,189
  • 1
  • 25
  • 27
  • 2
    I would use -[UIImage imageNamed:] here, but yeah same idea. I think it's possible to change the offset as well, but don't recall exactly. – Andrew Pouliot Sep 15 '10 at 20:21
  • 1
    This one is perfect. It's pretty weird that iOS allows an image to be a UIColor, but whatever. – jakeboxer Oct 09 '10 at 02:29
  • 16
    That would leak. Use this `backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"some_tile_image.png"]];` – Sam Soffes Jan 17 '11 at 23:33
  • This answer should be up voted above all the others. Just saying. – bentford Jul 18 '12 at 22:32
  • The image is correctly drawn and it is not upside/down. However it seems drawn from the bottom, because when I resize the window, it seems the bottom of the image is stuck to the bottom and the image slides out of the window from the bottom. Do you know how can I get the opposite ? – aneuryzm Feb 13 '13 at 08:28
16

Let's say you've got a CGImageRef for the image you want to tile called tileImage and a UIImageView called imageView. What you need to do is create a UIImage to assign to the image property of imageView. You can do that like this:

CGSize imageViewSize = imageView.bounds.size;
UIGraphicsBeginImageContext(imageViewSize);
CGContextRef imageContext = UIGraphicsGetCurrentContext();
CGContextDrawTiledImage(imageContext, (CGRect){ CGPointZero, imageViewSize }, tileImage);
UIImage *finishedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

imageView.image = finishedImage;

This will create a bitmap image context of the desired size, tile the image into that context, get a UIImage out of the context, then assign it to the UIImageView. You can really put this code anywhere so long as the image view and tile image are loaded and ready to go.

Alex
  • 26,829
  • 3
  • 55
  • 74
2

Rather than trying to modify a UIImageView, consider subclassing UIView instead. UIImageView is specifically designed for one non-tiled image and some of the internals may be messing you up. It's not really intended to be modified in the way you describe.

In a subclass of UIView (UITiledImageView?) you can use the drawRect: method to do what you want. You can even create ivars for the image, its size and tiling properties for greater flexibility and extensibility.

Updated with sample project: http://github.com/kailoa/6tringle-tiledimageview/tree/master

The relevant drawing code:

- (void)drawRect:(CGRect)rect 
{
    if (TiledImage) {

        //Since we are retaining the image, we append with ret_ref.  this reminds us to release at a later date.
        CGImageRef image_to_tile_ret_ref = CGImageRetain(TiledImage.CGImage); 

        CGRect image_rect;
        image_rect.size = TiledImage.size;  //This sets the tile to the native size of the image.  Change this value to adjust the size of an indivitual "tile."

        CGContextRef context = UIGraphicsGetCurrentContext();

        CGContextDrawTiledImage(context, image_rect, image_to_tile_ret_ref);

        CGImageRelease(image_to_tile_ret_ref);
    }
}
amattn
  • 10,045
  • 1
  • 36
  • 33
1

Sorry for not knowing how to add comment to other's answers, so I created a new answer here:

I just want to point out the answer provided by Kailoa Kadano has a bug, the image_rect.origin is not initialized properly.

About 3 weeks ago, I copied his code in my project, and it seems working. However, yesterday, I tried to run the code in ios simulator(iphone 4.3), it just hang in CGContextDrawTiledImage. After adding the following line as showed in keremk's answer:

image_rect.origin = CGPointMake(0.0, 0.0);

it works again!

It's rather tricky, actually at first I tested under iphone 4.3 simulator, then recently I tested under iphone 4.0 simulator, then yesterday when I switched back to 4.3 simulator or 4.2 simulator, the problem occurs. That is the image_rect.origin is undefined, sometimes it's zero data, maybe sometimes it has some random data.

xiangz
  • 19
  • 1
0

I recently did this by creating a custom UIView.

@interface TiledImageView : UIView {
@private
    UIImage *image_;
}

@property (nonatomic, retain) UIImage *image;
@end

and for the .m file:

@implementation TiledImageView
@synthesize image = image_;

- (void)dealloc {
    [image_ release];
    [super dealloc];
}

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Initialization code
        self.image = [UIImage imageNamed:@"BGTile.png"];

    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    // Drawing code
    CGImageRef image = CGImageRetain(image_.CGImage);

    CGRect imageRect;
    imageRect.origin = CGPointMake(0.0, 0.0);
    imageRect.size = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));

    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextClipToRect(context, CGRectMake(0.0, 0.0, rect.size.width, rect.size.height));  
    CGContextDrawTiledImage(context, imageRect, image);
    CGImageRelease(image);
}

@end
keremk
  • 2,303
  • 14
  • 10