Let’s imagine you’re building an application for really tough guys. A motorbike shop. Located on the active volcano 🌋. On the island full of zombies 👤. In the middle of the acid ocean 🌊. On an alien planet 👽. In an inversed space-time dimension 💫. Diffused shadows and all the “paper” things are not tough enough for that. They even hardly agreed to create an app for their business, by the way. They simply wanted to enslave a whole civilization to send an arrow-ad man to every corner in the galaxy, to advertise their shop and record bookings for their roaring monsters, but somebody told them it would be bad for PR 😶.

When you visited their shop first time, you thought you might have recognized one of your discoveries in “No Man’s Sky”

So it’s really tough, and you have to stand to it.

So you present them with this first version of the app (starting source code under the link).

That button…

Reviewing login and signup screens, and slowly getting to the holy grail of this application — bikes catalogue.

And everything goes relatively well (you’re not beaten to death with your limbs dismembered from your pathetic body). Well, until something really bad happens…

“IT IS BLUE!” — proclaimed by one of your clients. You see that for sure and preparing yourself to hear about the penalty for such an obvious mistake. But then the face of shop owner changes and its usual anger and rage сedes place to curiosity, while he says: “IT DOESN’T FEEL LIKE US, LITTLE HUMAN”.

“THIS SMALL PIECE OF PAPER WON’T SURVIVE HERE LONG” he adds.

And that it’s true, in fact, your spacesuit beeps of life support system malfunction for the last 20 minutes.

“USE METAL”, says the owner visibly proud of his savvy eye. “BRUSHED METAL, WE WANT OUR CUSTOMERS TO BE EXCITED.” and falls silent.

The rest of the presentation goes smoothly and you happily depart in one piece. What a trip.

“Brushed metal texture” is what your first search query looks like the next day. But nothing looks quite like you want to see it. Some textures have unnecessary gradients, some just look boring and washy, some doesn’t have scratches look nice enough. Everyone was there. Time goes by as you understand — it’ll be quicker to write it yourself then find what you need.

Luckily Flutter allows you such freedom. You start with scaffolding a CustomPainter for this BikeButton .

And keep the BikeButtonPainter itself simple, for now.

Also, the whole button container was very flat, so you add a bit of depth to it, explaining where the list goes when it scrolls behind the button.

We can only hope this shadow is not too soft for them.

Not that bad you think, yet someone still has to brush that chunk of grey boringness. Brushing metal is very simple, you just need a very stiff brush and a lot of patience. Or an electric tool to create that linear motion. To re-create that look, you think that semi-transparent lines might do, overlapping each other randomly.

For that, you add a new helper in BikeButtonPainter to return an arbitrary Offset within given Size .

As well as new paint, to draw those lines.

And simply generate a few of these lines in the button body you got.

The result is disappointing. At best. You feel that a tiny cold worm starting to unroll itself somewhere in your stomach. “More lines,” you think.

But despite tenfolding the line count… It doesn’t look ten times better. The worm grows bigger and colder.

“Maybe even more lines?” you think.

But that just leaves you to stare to a white mess. There’s no button anymore.

You realize that there could be too many lines. “How do I find the optimal count to fit all sizes? Maybe I can compute count based on the size itself?”

That’s looking a bit better already, allowing you to customize how the texture looks, regardless of its area.

Then, you think that the current brush is a bit too random, in reality, all the scratches would be aligned almost precisely. So instead of two random points, you decide to choose only one and add another one with a stricter rule.

Luckily, Dart allows doing that easily. Offset class implements most of the algebraic operators, so you can just do all the cool vector addition inline!

So, now, you align the points on a straight horizontal line.

Someone applied “wind” effect to this button.

And the button now looks like it tries to escape your application before it’s too late.

You think that one of the easy ways to fix this behaviour is simply to clip unwanted parts of the texture. And that couldn’t’ve been simpler with Flutter.

Alongside the Flutter itself being a cake 🍰, dart:ui Canvas is sort of cake too, when it comes to drawing on it. Your usual workflow is to call canvas.save() , then apply modifications you created a layer for, and then call canvas.restore() . Simple and elegant.

So, in this case, you want to clip drawn area to the size of your button.

Looks a bit better, but now it’s asymmetrical. To fix that, you want the lines to start and end in equal areas from the rectangle borders.