Dynamic drawing and 1px lines on iPhone 6 Plus

As many of you probably know by now, iPhone 6 Plus has a higher pixel density and now required @3x imagery to provide a crisp UI experience. I am big fan of dynamically drawing UI elements, button background, segment dividers, and many other elements in code. While this approach may seem limiting with what kind of UI elements it can provide it is, in fact, quite capable of delivering good quality art work for relatively simple use cases. The drawing itself is very fast, and only done once per image because we store the output UIImage into a static variable where we can later retrieve it for reuse. Using this technique should be limited to small, resizeable graphics that don’t consumer a lot space in memory because we are dealing with finite resources on iOS.

A quick example of such a technique is the following screenshot of a red notification circle used on a custom menu button. Both the 3-stripe menu button and the red notification circle are drawn in code.

The example above is two-fold. Since the red notification bubble can appear and disappear depending on the number of notifications, both the menu button image and the red bubble must be two separate images. Lets begin by drawing the menu button.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

-(UIImage*)menuButton{

// Use a static UIImage to store the finished result image

staticUIImage*_menuButton=nil;

// If we have an image already assigned, return it and avoid doing all that work again

if(_menuButton!=nil){

return_menuButton;

}

// Setup some sizing variables

CGFloatspacing=4.0f;// Spacing between each menu button strip

CGFloatstripHeight=1.5f;// Height of each menu button strip, total of 3

Voila! We’ve got ourselves a menu button, but we have a problem. Notice our stripHeight is 1.5f. While this may appear perfectly fine on @2x devices such as the iPhone 6 and iPhone 5S because 1.5 points translates into 3 pixel on screen, on devices like iPhone 6 Plus 1.5 points translates into 4.5 pixels. Since devices these days aren’t very good at rendering on half-pixels, we’ll get a distorted, blurry image. Not good. To work around this problem we’ll employ the screen scale to provide more accuracy for our rendering. We already know that our desired strip height is 3px. With this in mind, we can calculate what this value will be in points like this:

1

CGFloatstripHeight=(1/[UIScreenmainScreen].scale)*3.0f;

This may seem a little redundant as that will essentially translate into 1 / 3.0f * 3.0f but using this approach we won’t ever have to worry about rendering on half a pixel provided that we use whole numbers for 3.0f value. This is also a very good way to render single pixel lines, exactly like those used in UITableViewCell dividers starting in iOS 7. By setting line height to equal (1 / [UIScreen mainScreen].scale) * 1.0f, we can be certain that we’ll get a 1px line regardless of the screen scale.

The end result – pixel perfect images without a trip to Photoshop. The beauty of this approach is that changing color, line thickness, and other details is as easy as swapping values. No need to go through a lengthy Photoshop workflow of modifying the image, saving it and moving into your Xcode project. Again, you must be careful not to render large images and store them into static variable as it can have a detrimental impact on your application’s memory footprint. With that in mind, this method is excellent for small images. I especially love this solution for resizeable used in buttons, table cells, and other classic UIKit elements.