Gradient Label

Suppose you needed to post text to describe an image.  Like a Facebook post for example.  What color of text do you choose?  If you choose black, the text would be washed out for any dark images.  Conversely, if you choose white, the text is washed out for any light images.  You could sample the image, find the average color and take the inverse.  However this falls short on drastically contrasting images (like an image of black and white stripes), since the average image may come out nearly white (or black) and yet the text could cross over the light/dark portion of the image and get washed out.  What to do?

Well, after heavy consideration, I decided to stop trying to figure this out and look at what the professionals did.  From Facebook:

facebook_example

So it looks like they are placing a gradient behind white text.  So that is what we are going to be doing today.  Creating a label with a gradient background.

Lets get started.  Begin by firing up Xcode and starting with a Single View Application.  Name and save it what and wherever you like.

Now, go into Storyboard and add an image view to the view controller, and add this image: Stripe to the image view.  (Right click and choose download to save the image).  At this point your storyboard should look like this:

How your storyboard file should look after getting all set up and stuff!

How your storyboard file should look after getting all set up and stuff!

Great, now lets add a label: add this code to your viewDidLoad method inside the ViewController.m file:

 

Hit run and see how it looks.  Pretty terrible huh?  Now comes the fixing part!

When I was first working on this, my initial solution was to add a CGGradientLayer to the label.  However, this obscures the text.  Then next solution I came to was to add the label to a view and add the gradient layer to the view.  However this is cumbersome and not very reusable.  Of course you could subclass the UIView class which automatically adds a UILabel/UITextView/UITextField with the same frame as the view.  But then you need to either expose the label, textView, or textField, or all of their properties.  No, these were all terrible ideas.  What we really want to do is to subclass the UILabel/UITextView/UITextField classes and override the drawRect function.  We will do this for the label below but the code for the other classes is identical.

UILabel Subclass

Add a new file to your Xcode project and make it a subclass of UILabel, call it GradientLabel.  Now, uncomment the drawRect function.  Replace the guts of the drawRect with this code:

Lets go over what is going on here.

  1. We create a new CG (Core Graphics) context reference and save the current state (so we can restore it once we are done with our work).
  2. We create an array of the colors we want to use in our gradient.  Note that we are using the CGColors inside the array (hence the (__bridge id)).  Next we create a color space reference to use for our gradient and then create a gradient reference (again casting the colors array into the CG world).
  3. We create starting and ending points for our gradient.  In this case, since we want the gradient to fade gradually down the label, we start it at the top middle, and end it at the bottom middle.
  4. We draw our gradient with the information we created in steps 1-3.
  5. We release the objects we retained (we need to do this since the core graphics references are not handled by ARC.  With the memory cleanup done we restore the graphics state we saved in step 1.
  6. Finally, we call the super drawRect function.  If we neglected to do that, we would have a nice gradient but nothing else.

Now go back to your view controller and import the GradientLabel class and change the class of the UI label to the gradient label:

Run the application and it should look much better, though it’s still not great.  Lets change the text to white by placing  [gradientLabel setTextColor:[UIColor whiteColor]]; right after the setTextAlignment method.  Run again and it should look like this:

iOS Simulator Screen Shot Jun 23, 2014, 10.08.11 AM

Looks pretty good.  Now there is a lot we could add at this point.  We could make public properties of the gradientColors, locations, options, start point, and end point.  We could also add a radial gradient option.  If you want to go through all the work your self, its not too bad, if you would like to cut to the chase, I’ve done the work for you.  Download the source code for this project below, along with the finished gradient Label, textView, and textField subclasses.

Example Project

Subclasses 

Hello World!

So, I’ve decided to blog.  And by blog, I mean provide an ongoing  status update of the technical adventures I have.  I might discuss my forays into Flex & Bison, or perhaps delve into my experiences with using a UIPageViewController.  It might be fun.  It might be useful.  But whatever it is, it is what I do and I hope it is of use for you.

Enjoy!