66

I have a fullscreen background image that is tiled, i.e. it has to be reproduced a few times horizontally and vertically in order to make a big one. Like in the browsers on ugly home pages ;)

Is UIImageView my friend for this?

Thanks
  • 40,109
  • 71
  • 208
  • 322

7 Answers7

105

If I understand your question correctly you can use colorWithPatternImage: on UIColor then set the background color on a UIView.

If you must use a UIImageView you can do the same but whatever image you place in the image view will draw in front of the tiled image.

Vaibhav Saran
  • 12,848
  • 3
  • 65
  • 75
Bill Dudney
  • 3,358
  • 1
  • 16
  • 13
  • Thanks! Well what I want to do is: I have an image file with a pattern, that can be repeated vertically and horizontally. I want to repeat this image pattern on my screen. Maybe it saves some memory. – Thanks Jul 14 '09 at 20:05
  • 1
    If you use the UIColor method outlined you will get your screen filled with the pattern image. There are more complex ways but from your description this should work. – Bill Dudney Aug 10 '09 at 16:53
  • Hi, this works, but the Alpha of the Image doesn't work. :( Any solutions – Rajavanya Subramaniyan Oct 08 '10 at 14:37
  • [[UIColor colorWithPatternImage:...] colorWithAlphaComponent:...] – titaniumdecoy Nov 14 '11 at 19:57
  • 1
    Can we set the colorWithPatternImage through xib rather than through coding? – user4951 Jan 26 '12 at 10:39
  • @JimThio Nope, you have to do it with code. If I'm wrong someone please comment. – ManOx May 28 '12 at 06:48
  • For years I was doing it this way (colorWithPatternImage:) but Apple has fixed this in iOS6 to add the missing feature. And there's a way to make it work on iOS5 etc - c.f. answer below – Adam May 10 '13 at 10:39
30

To get alpha to work with pattern image, make sure you have the following set:

view.backgroundColor = [UIColor colorWithPatternImage:aImage];
view.layer.opaque = NO;
Ryan Brodie
  • 6,554
  • 8
  • 40
  • 57
Kyle
  • 301
  • 3
  • 2
20

In WWDC 2018 video session 219 - Image and Graphics Best Practices, Apple engineer explicitly recommends not to use the pattern color for tiling backgrounds:

I recommend not using patterned colors with a background color property on UIView. Instead, create a UIImageView. Assign your image to that image view. And use the functions on UIImageView to set your tiling parameters appropriately.

So the best and simplest way to create a tiled background would be like this:

imageView.image = image.resizableImage(withCapInsets: .zero, resizingMode: .tile)

Or even simpler, if you use asset catalog – select your pattern image asset and, in the Attributes inspector, enable Slicing (Horizontal/Vertical or both), set the insets to zero, and width/height to the dimensions of your image:

then simply assign this image to your image view (Interface Builder works, too), just don't forget to set the UIImageView's contentMode to .scaleToFill.

maxkonovalov
  • 3,651
  • 34
  • 36
  • This one didn't work for me when I used vertical slicing with a top inset of 0. Xcode 11.3.1 (11C505). I submitted a bug report for that. – Anton Plebanovich May 22 '20 at 14:03
  • Hmm, strange, it shows correctly in IB but on the device is shows default `scaleToFill` :/ – User Jun 08 '20 at 19:07
  • Update: This was because devices and simulators apparently cache the launch screen/images (even after reinstalling). It worked on another device. – User Jun 08 '20 at 19:15
17

For years I used Bill Dudney's approach, but iOS 6 has a much better solution. And ... today I found a way to make this work on old versions of iOS too.

  1. create the new class "UIImage+Tileable" (copy/paste source below)
  2. import this in any class where you want a UIImageView with tileable image. It's a category, so it "upgrades" all your UIImage's into tileable ones, using standard Apple calls
  3. when you want a "tiling" version of an image, call: "image = [image imageResizingModeTile]"

UIImage+Tileable.h

#import <UIKit/UIKit.h>

@interface UIImage (Tileable)

-(UIImage*) imageResizingModeTile;

@end

UIImage+Tileable.m

#import "UIImage+Tileable.h"

@implementation UIImage (Tileable)

-(UIImage*) imageResizingModeTile
{
    float iOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];

    if( iOSVersion >= 6.0f )
    {
        return [self resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode:UIImageResizingModeTile];
    }
    else
    {
        return [self resizableImageWithCapInsets:UIEdgeInsetsZero];
    }
}
@end
Adam
  • 32,900
  • 16
  • 126
  • 153
  • Nice solution, any idea to use this for iOS 4? – Christoph May 29 '13 at 23:13
  • I thought this worked on iOS 4+, sorry. It definitely works on 5+. Test with 5 and make sure it's not something else that's wrong (I had a few subtle bugs first time I did this). If it works on 5 but not 4, you'll have to write your own tiling code (this takes about 15 minutes to write and debug: make a custom UIView that draws a grid of UIImageViews ... or even better, make a custom CALayer that implements the drawInContext call and splats a raw CGImage multiple times) – Adam May 30 '13 at 14:29
  • Well, it does not work on <5.0. Nice solution, but I did go for `[UIColor colorWithPatternImage:...]` then. – Christoph May 30 '13 at 18:31
8

I use a variation of @Rivera's solution:

Put the following in a UIView extension:

- (void)setColorPattern:(NSString *)imageName
{
    [self setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:imageName]]];
}

Then you can set the background pattern in the storyboard/xib file: Image showing how to set the colorPattern in the storyboard/xib

Daniel T.
  • 32,821
  • 6
  • 50
  • 72
  • 3
    This is a great solution but note that it will not work in a Launch Screen xib file. "error: Launch screens may not use user defined runtime attributes.". – Jon Steinmetz Sep 12 '15 at 16:55
4

As I really like Interface Builder I created this UIImageView subclass to apply tiled backgrounds:

@interface PETiledImageView : UIImageView

@end

@implementation PETiledImageView

- (void)awakeFromNib
{
    [super awakeFromNib];

    UIImage * imageToTile = self.image;
    self.image = nil;
    UIColor * tiledColor = [UIColor colorWithPatternImage:imageToTile];
    self.backgroundColor = tiledColor;
}

@end

I tried overriding setImage: but it seems IB doesn't call it when decoding a Nib file.

Rivera
  • 10,792
  • 3
  • 58
  • 102
0

Swift version of Daniel T's solution. You still need to set the keyPath value in IB. Of course you could be more careful unwrapping the Optional UIImage.

extension UIView {
    var colorPattern:String {
        get {
            return ""  // Not useful here.
        }
        set {
            self.backgroundColor = UIColor(patternImage: UIImage(named:newValue)!)
        }
    }
}
Andrew Duncan
  • 3,553
  • 4
  • 28
  • 55