No-fuss reflections – generating reflections the easy way in iOS

by Robin Summerhill on August 25, 2011

How to add reflections to your iOS UI is one of those questions that keeps popping up on developer forums. Used judiciously it can help you achieve that ‘polished’ look, increasing the visual separation between UI elements and the background, and creating an illusion of 3D space. Apple provides sample code to get you started, showing you how to create a reflection of a UIImageView.

In this article, we show you how to extend this technique to generate reflections of any UI element or collection of elements including image views, labels or even a UIWebView. The reflection generation is wrapped up into a canned solution that you can drop into your project and design using Interface Builder.

The sample code

A demo is provided that allows the user to navigate through a selection of sample images. Each image is displayed along with its filename and a reflection is generated whenever the user steps to a new image. Source code for the demo is available on GitHub or can be downloaded as a zip archive.

How to use in your own projects

To add reflections to your own project first add the ReflectionView header and implementation file from the demo project (ReflectionView.h and ReflectionView.m). ReflectionView is a UIView subclass that is designed to be used as a container view. Any subview placed in the container will be reflected below the container.

Next, use Interface Builder to lay out your UI. To add the ReflectionView container, drop a UIView onto the canvas and then change the class of the UIView to ‘ReflectionView’ using the Identity inspector. Because the reflection will appear below the ReflectionView container and outside of its bounds it is important to ensure that the ‘Clip Subviews’ attribute of the ReflectionView is deselected. This attribute appears in the Attributes inspector. Of course, it is also possible to create the ReflectionView programmatically without using Interface Builder.

Now, drop the required interface elements into the ReflectionView container. In the demo we dropped in a UIImageView and a UILabel. We also set the sizing attributes appropriately so that the UIImageView and UILabel would respond to changes in the size of their parent view, for example, when rotating from portrait to landscape.

Setting the ReflectionView class in IB

Now go ahead and connect your Interface Builder elements to outlets on your view controller as usual. You will also need to set up a ReflectionView outlet in addition to any other controls and subviews. You do this so that you can signal from your view controller when the reflection needs to be regenerated.


ReflectionView exposes three properties that can be used to modify the appearance of the reflection. These should be set from your view controller; viewDidLoad would be a good place to do this.

  • reflectionHeight: the height of the reflection in display points (defaults to 60)
  • reflectionOffset: the size of the small vertical gap between the bottom of the ReflectionView container and the top of the reflection (defaults to 2 display points)
  • reflectionAlpha: the global transparency of the reflection (defaults to 0.5)

Regenerating the reflection

The last thing that you need to do is ensure you call -[ReflectionView updateReflection] whenever the visual appearance of the ReflectionView container changes. In the demo we do this after updating the image displayed in the UIImageView and updating the UILabel to show the filename of the image as shown below.

- (void)displayImage:(NSUInteger)index
    self.imageView.image = [UIImage imageWithContentsOfFile:[_imagePaths objectAtIndex:index]];
    self.label.text = [[_imagePaths objectAtIndex:index] lastPathComponent];
    [self.reflectionView updateReflection];

To see the reflections in use in a commercial app take a look at our photo viewer app Showtime. We use reflections in the theme selection UI underneath previews of each theme.

Reflections seen in the wild - Showtime theme selector

How it works

When a ReflectionView instance is created, either programmatically or via a nib file, a UIImageVIew subview is created to hold the generated reflection. This UIImageView is positioned below the ReflectionView container with an offset specified by the reflectionOffset property. Its height is specified by the reflectionHeight property. -[UIView layoutSubviews] is also overridden to ensure that the UIImageView is repositioned whenever the size or position of the ReflectionView container changes.

The actual generation of the reflection is performed by -[ReflectionView reflectedImage]. This method is based on code from the Apple Reflection sample code and works in a similar way. A bitmap context is created in which to draw the reflection. A vertical grayscale gradient is then created and applied to this bitmap context as a mask. This produces the required fade-out towards the bottom of the reflection. The contents of the ReflectionView are then rendered into this context using -[CALayer renderInContext:]. This method renders the receiver and all its sublayers into the specified context. One subtlety is that the call to renderInContext must be bracketed with calls to CGContextBeginTransparencyLayer and CGContextEndTransparencyLayer to ensure that the mask and alpha effects are applied to the contents as a whole rather than being applied individually as each sublayer is rendered.

- (UIImage *)reflectedImage
    CGContextBeginTransparencyLayer(ctx, NULL);
    [self.layer renderInContext:ctx];

To support the higher resolution display of the iPhone 4 a reflection is generated at twice the required size in display points. The display scale is detected at runtime by checking if UIScreen supports the scale property and using this value if it is supported or defaulting to 1.0 if it is not.

- (UIImage *)reflectedImage
    // Calculate the size of the reflection in devices units - supports hires displays
    CGFloat displayScale = 1.0f;
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
        displayScale = [[UIScreen mainScreen] scale];

If you are wondering how the rendered image is reflected vertically without applying a transform to the context then take a look at the Quartz2D and CALayer coordinate systems. The Quartz2D default origin is at bottom left and y axis increases up the screen. The CALayer default origin is at the top left and the y axis increases down the screen. We are rendering a CALayer (using the CALayer coordinate system) into a Quartz2D context (using the Quartz2D coordinate system) so get the vertical flip for ‘free’.

Robin Summerhill is a tech blogger, developer and architect. He is co-founder of Emu Analytics where he is currently working as Head of Technology.

Links to demo source code

Git –
Download zip –

Share and Enjoy:
  • Print
  • email
  • Digg
  • Facebook
  • Google Bookmarks
  • Reddit
  • Twitter

Previous post:

Next post: