Flexible Tooltips in iOS

Evandro Harrison Hoffmann
Level Up Coding
Published in
7 min readFeb 12, 2020

--

Have you ever had a case, that once your UI is done, implemented, all animations are working, pixel-perfect, beautifully aligned and resized to all screen sizes, exactly as the designs. You are so proud of your work and finally you can brag about it to all your colleges while having that well deserved cup of coffee when your designer comes to you and tells you: "There’s one more thing!".

And that one more thing is actually a tooltip tutorial, with a few rules:

  • The background will dim to black
  • The item has to remain highlighted, meaning that it should NOT be dimmed
  • The tooltip has to be aligned to the item, no matter where it is presented on the screen

That’s the time you put your coffee down (because you don’t want to burn yourself 😅) and think to yourself: "Oh no!! Now what!??"

In this article, we will talk about a few possible solutions and also one that we came up within my team, that ended up solving the problem to any view structure or size of screen 😀.

As you can see in the pictures above, the tooltip added highlights the item we add it to, dimming the rest of the content.

And you start thinking of possible solutions:

  1. Ignore your designer and just add the tooltips without the dimmed background: 😂😂😂 who never, right?
  2. Place an image with the tips on top of the screen: This could work if we had a single size of screen (ooh, good times when it was only 1 iPhone and 1 iPad 😂), but considering that we have a range of different screen sizes, it wouldn’t be practical to handle each one of them separately.

3. Mask the view you want to highlight, put the dimmed view on top of the entire screen, and cut out the masked frame: This could work, but it seems too complicated to me. Next?!! 😅

4. Finally, the solution I want to talk about: Snapshot the view to highlight, add the dimmed view on top of the screen, place the snapshot on top of it, and present tooltip. Awesome! We have a winner!!! 🎉🎉🎉

The snapshot solution

Ok, so let’s recap:

  1. Snapshot the view to highlight
  2. Add a transparent-black view on top of everything, to make it dim
  3. Place an image view with the snapshot on top of the dimmed view
  4. Show the tooltip from the component

At this moment you might have telling yourself: "Of course, that makes sense!!!". So all that’s left is for us to check on how we make it happen! 😀

The implementation

Ok, so to start, we’ll take the snapshot of the view we want to get highlighted, and nothing more. Here’s how to do it:

Then all you need to get the image from the view you want, is to use myView.snapshot. And the magic has happened! 😎

Awesome! Meaning now, all we have to do, is to place the view in the exact same spot as it is located, no matter what layout structure we are using. How to do it you say? Thought you’d never ask! 😁

Here we have 2 functions, to add the snapshot of a view to a parent view and to remove it. addSnapshot will do all the work for you, meaning that it will take the snapshot of a specific view and add it to the view we are calling it from. Example:

Consider this screen, that we want to snapshot the button and place it in the main view. We would simply call: parentView.addSnapshot(of: button). And the magic has been done 🧙‍♂️😀. And to remove, simply: parentView.removeSnapshots().

But then, you might be thinking, in the example above, it seems like the layout structure isn’t complex at all, adding a snapshot to the right place wouldn’t be so hard. This is where it gets interesting here, because we are using globalPoint conversion, the view will always be placed exactly where it looks to be, no matter where it is, works even with views inside of cells 😎.

Great, we have our snapshot, next step? Dim the main view and place the snapshot on top of it. Let’s see how:

Like for the snapshot, we have 2 functions here, to add the dark view and to remove it. Adding will constraint it to the full size of the view and fadeIn, that is nothing more than animating the alpha to 1. Here’s the code in case you are curious: 😀

Having said that, what we want now is to add the dark view and then add the snapshot on top of it, and here’s how:

  1. parentView?.addDarkView()
  2. highlightView?.addSnapshot(in: parentView)

And this is what you should have as result:

Awesome! Now, all we have to do is to add the tooltip view on top of everything and we are good to go! Let’s get to it!

The tooltip view

The goal here is to build a tooltip that could be either facing down or up (or any other direction that your application requires). We will make it simple, only with text and a button for moving to next or closing the tooltip.

And to make it more visual, I’m going to build it in a XIB file and call it from the code. The Indicators are basically arrows to each direction the tooltip could be pointing to.

And here’s how it looks like in Swift:

Nothing too fancy here, just added the components reference, added timeout function and a callback to be called once it disappears from screen. Important thing for us to make it flexible using constraints is to make translatesAutoresizingMaskIntoConstraints = false. This will make sure the view can be placed anywhere and respect the constraints we will later add.

We can define the possible directions of the tooltip in an enum:

Once the view is created, we can then add a simple initialiser from a UIView extension to show the tooltip with the items we want:

Then we need to constraint the view and indicator based on the direction of choice:

Add constraints for the view not to go beyond the screen borders:

We can then finally present the tooltip and setup the timeout (in case users don’t tap to close):

And the result is:

Done, you now have a fully working flexible tooltip engine in your code. Tell your designer to bring on all tooltips they can imagine because we are ready for them!! 😎🚀

The full code is available in GitHub, it contains a tooltip manager that I’ll later talk about in another article. I hope you have enjoyed and that it was helpful to you! Happy coding! 😁

https://github.com/eharrison/MagicTooltips

--

--