From the blog

Linear Interpolation and Fading Hairlines

Linear interpolation is a simple method of finding intermediate values between two endpoints. It has numerous applications in computer graphics, where it is known as lerp, but we are going to use a tidy Swift implementation to add some subtle polish to an iOS app.

You can download the source code for the example app if you want to follow along.

The Design

Let’s say we have a table view in our app. Our designer wants a clean, no-frills design, so there is no divider between the status bar and the table view:

A scrolling table view with nothing visually separating the cells from the status bar

Unfortunately, when the table view scrolls, the text scrolls out of sight at a seemingly arbitrary point. As developers, we know that it’s the bottom of the status bar, but to the user, the disappearance feels unmotivated. It would be nice to have a thin line, or “hairline,” separating the status bar from the table view:

Acquiring Numbers

Now the text has a reason for disappearing. Great! However, our designer doesn’t like the hairline being there all the time. They want the hairline to start out invisible, and fade in smoothly as the user scrolls. And they don’t want to just animate it in and out with fixed timing; they want its opacity to be a function of the scroll position.

Fortunately, we can solve this pretty easily using linear interpolation. It’s normally used for picking intermediate values along a line between two points. However, we can also do the reverse: pick points along the line, but then remap those points to the same relative position on a line between two different endpoints. What does this look like in practice?

Measuring the Scroll View

In the screen recording above, check out the console in the background. It’s printing the result of this function, where I’ve implemented scrollViewDidScroll(_:) and added a print statement:

I know I want to control the alpha of the hairline view, which is on the range 0...1. What I’m looking for in the screen recording are which positions of the scroll view I should use as my start and end points. I’d like to give a bit of a buffer before I start fading in, so I’ll start at 3 points, and it looks like the content offset is at about 11 points when the text is about to hit the hairline, so I’ll use 3...11 as my input range.

Float Remapping with Linear Interpolation

You can read about the equations for linear interpolation on Wikipedia, but we’ve encapsulated this particular use case in a nice Swifty wrapper as part of our Swiftilities grab-bag of Swift utilities for writing iOS apps. The implementation details are outside the scope of this post, but feel free to use the linked code in your own projects. Here, we will use it to implement the desired fading behavior in one line of code:

OK, I exaggerated a bit about one line of code. We need to extract the useful piece into a function so that we can call it from viewWillAppear(_:), or else the hairline’s alpha won’t get updated until the scroll view scrolls for the first time. But let’s take a look at the line where the magic happens: the FloatingPoint.scaled(from:to:) instance function from Swiftilities:

Swift’s use of the ... closed range operator helps make this statement compact and easy to read. The scaled(from:to:) function takes a floating point number in the from range and linearly interpolates it to the same relative position on the to range. If that’s not clear, perhaps an illustration will help:

Illustration of using linear interpolation to map a floating point number from one range to another

Now, the hairline fades in and out smoothly as a function of the scroll position, so it’s always moving at exactly the same speed as the user. It’s a simple, easy way to add a little bit of delight and playfulness to any app.

Fading Hairline

Case Study: Analog Clock

Once I had this tool at my disposal, I started to notice other places where a clean syntax for linear interpolation fits neatly into my code. For example, I was recently writing code to draw an analog clock using UIKit, with rotated UIImageViews for the hour and minute hands. Once I had the time modeled as hours and minutes, the code to determine the angle of each hand, in radians, became surprisingly simple. Even with extra descriptive names and comments for this blog post, It’s still quite compact and readable:

For each clock hand, we are determining the current value, and then mapping it from the range of possible values to the range of [0...2π], which represents a full rotation in radians. From there, actually using the values becomes trivial:

I hope these examples give you some ideas for how to use linear interpolation in your own apps. The convenience of encapsulating linear interpolation into a compact, easy-to-read function makes it easier to throw it in where you need it, without worrying about muddying the code with extra visual and cognitive complexity.

Get In Touch

Raizlabs believes in improving lives through design and technology. We would love to work with you on your next project. Contact us!

Leave a Reply

Your email address will not be published. Required fields are marked *