Fancy picker: story of one background
I am currently working on an app that doesn’t have a lot of features, but is full of custom user interactions and visual effects.
Sometimes when you get something like this from a designer, you don’t know where to start. In this case I started with a horizontal picker, but that’s too boring for a blog post, so let’s skip it. Next thing that looked complicated, but turned out to be pretty easy to implement, is this nice gradient on the background.
So I had this design as a starting point:
And a horizontal picker (or for now just a plain collection view, to simplify the example). You can check the code in the playground.
And my task is to add a gradient background that will update when the collection view scrolls. Below is a GradientView I started with. Nothing magic in it, just overriding the draw(_ rect:) — what can be easier?
Here is my model by the way:
Now we can combine the gradient and the collection view in a Picker view and add it to the playground:
Nice! All we need to do is to update the gradient colors depending on the current contentOffset of the collection view.
First of all we want to be notified when scroll happens. Then we need to know what part of the content is visible right now. I added a visibleRange property and some delegate calls to the collection view:
Now we need to catch and handle scroll events and update the gradient. We can do it in the Picker class.
Clipping a gradient is pretty easy if you are using an RGB color model.
Hey, it is working! But looks a bit boring, design was better. Here you don’t even see the gradient anymore and the more items we have, the less noticeable it will be. What can we do with it? May be make the color range bigger?
OMG. May be not. May be some kind of a semi transparent black gradient on top?
Nah. It just looks like a boring semi transparent black gradient on top...
My solution was to use a blend mode. If you’ve never tried them before, you should! You define how two layers are combined and the effect can be very interesting. I used CGBlendMode.overlay, but there are many more.
What it does is: it puts a gradient from white to black on top of the gradient we already had. Thanks to the blend mode, the image beneath becomes lighter where the white is and darker where the black is. I made this overlay semi transparent to reduce the effect a bit.
It took some time to figure out, but once done it is super easy and adds a nice special touch to the app.