I am really excited that Frenzy 3.0 was launched this week. This major release introduced a new UI to make sales and Drops more discoverable. Amongst all the new features and polish, I am really proud of the custom refresh animation that I worked on. Here I explain the journey from prototype to completion.

The Final Animation
click to play

CAShapeLayer is amazing because it provides any easy way to animate stroking a path by adjusting the strokeStart and strokeEnd properties. My first thought was to Google “uifont to cgpath” and, of course, the first link was to an SO post with a simple function to do just that.

However there were two main problems:

  1. The Frenzy logo is based on a font but has modifications to combine the “f” and “r” done in Illustrator, so we couldn’t just use the font directly.
  2. And even if we could, the path generated by this function represents the outline of the letter. This means that when the renderer tries to animate filling the path, it has no idea which pixel should or shouldn’t be filled for the current keyframe, which results in all-or-nothing fills.

I knew the best result would be if the letters were stroked. Nevertheless, I began making a prototype using the SO code to see far I could get with as little custom code as possible.

I created a playgrounds file which animated the drawing of a single letter. Having a grasp of the concept, I then created separate layers for each letter. Since the canonical version of the logo that we had was in Illustrator, I generated the bezier paths using PaintCode, which was a timesaver. This is how it looked:

Outline Style
click to play

Although a bit better than the default spinner, this wasn’t in line with the frenzy brand - the use of an outline and white fill looked out of place


The real problem was that we needed some way of representing the stroke path of the letters. Although we probably could have created a replica of the logo by combining (many!) bezier curves with varying line widths and animating it, this would be a lot of effort and detail for an animation that will be displayed fairly small in size.

Instead we can get a very good approximation by stroking the rough path of the letters and clipping to the actually outline of the logo. At the size that the custom refresh was being displayed, this was good enough.

More Polish

Again, using CAShapeLayer makes it really easy to tie the tableview scroll offset with the stroke-completion amount. Although not obvious, the timing for the erase-then-stroke animation was heavily tweaked so that it paused long enough to emphasize the logo, but quick enough so it wouldn’t become cliché. Lastly, the logo will always complete the full animation loop before being hidden, even if data came back midway in the animation cycle. This gives the impression that each animation is deliberate and refined.

I have always loved working on the subtle polish features that create an ah-ha moment for users. I am very proud for this to be my finale feature in both senses of the word. The past year has been filled with great memories and experiences with the whole team. I enjoyed every moment and learned a lot in every aspect. Although I will miss the team, I know they will continue to iterate on the product and gain new collaborations. I look forward to seeing what’s yet to Drop.