Small update: I left out Option 4 (which I assumed, incorrectly, was implicit). Because of that I changed up the ending too :)
One of the great things about Flutter is that it allows you to create rich, design driven applications. The Material library is feature rich and the provided Widget creation mechanisms are powerful, quick and flexible. When I first got deeper into Flutter, my first thought was “This is awesome! It will be like iOS circa 8–9 years ago when everyone was being super creative”. That’s how powerful the Flutter mechanism is.
Oh, and you get it for two for the price of one!
End of story, right? No. Let’s get real, some people are not actively embracing these freedoms. There seems to be some confusion around how to approach the cross-platform aspects of your application. I want to try to clear this up by presenting you with a few options as to how to go about it, and to hopefully alleviate your fears in going your own way.
So, what are the options?
Option 1: Use Material
You can use Material for both iOS and Android. This is absolutely acceptable. It has been pretty well established that Material transcends Android and today is heavily used on the web and on iOS. You’re not breaking any rules. Sleep soundly.
It is true that ink splashes can look a bit out of place on iOS. I’ve had a few clients that have specifically requested “no material” which ultimately meant “no ink splashes on iOS please”. If that isn’t a problem, or you like the style, then you’re all set! Material everything.
Option 2: Platform “Wrappers”
I’m calling any Widget that chooses Material on Android and Cupertino on iOS a Platform Wrapper. This approach seems to be emerging as a fairly common pattern but I’m going to say that, in my opinion, its plain wrong in most cases. There, I said it.
Depending on how true to the platform you are, you will eventually bump up, hard, against platform/widget specific differences. Oh? Let’s consider buttons. On iOS, UIButton doesn’t allow for text and images. Should you faithfully replicate that? If not, why do you care if its a Cupertino button?
If you’re not faithfully replicating the iOS situation, then what’s the point of the Cupertino widgets? I would argue that they don’t have a lot of usefulness unless you’re specifically targeting iOS (as a single OS app).
Also, what if the underlying Widgets change? Will you keep updating your wrapper to fit? What’s the lead time on that? There is a giant can of worms with your name on it.
There are definitely times when it makes sense to do this, for instance for a Switch. You’re not going to remake a switch (I hope).
Option 3: Build something in-between
Ugh build it? Why would you make me do that? The answer is because it’s quick, easy and it’ll be a lot nicer in the long run. Besides, you only have to do it once and then it’s done. You can reuse it 500x in your app or in every app you develop after this one.
OK, but let’s be super clear. I’m not advocating that you go off and re-build the entire set of widgets provided in Flutter. That would be crazy. I am saying that you should pick high value interactions and visual elements that make sense for your application. What does this mean? Here are a few examples. The full list is a lot longer, but it’ll help to provide context:
- Navigation elements: You don’t have to use platform specific app/nav bars unless you want to. You should pay attention to iconography and placement of things like buttons and text though.
- Transitions: Flutter has a navigation paradigm that is closer to Android’s but is still unique. I’ve built enough UINavigationControllers to know that they have good bits and bad bits. I also know that you don’t have to replicate them if you don’t want. You can build your transitions different for iOS and Android if you want, or you can build them in a common way that works for your app.
- Button hit states: As discussed above, the “ink” effect is super common place on android and it’s generally expected. You don’t have to use it though. You just need to make sure that you have nice, complete hit states on all of your buttons. The animation below is from a button I use in all my projects:
For Android I use ink because it makes sense and I get that effect for free in Flutter. For iOS, I use a simple fade effect that is not standard on iOS because the iOS standard effects (the ones designed by Apple) are lame. All I need is to indicate to my users that they hit the button. How I do it is up to me.
In the end, the only difference is that there is a highlight state that is Android only. Everything else is identical.
In case you’re wondering, the button above took about 20–30 mins to make, is flexible, looks awesome and is available here.
All these options are great but Flutter, as I said, provides the tools to make interesting apps as well as more “boilerplate” experiences. As I outlined above (Option 3) you can pretty easily tweak core experiences to make them your own while keeping with the general sense of what is idiomatic within iOS and Android. But we can take it further …
Option 4: Be creative
A great example of getting creative is Clear Todos. When it first came out it was big news. It looked awesome, it was interesting and it was a super creative solution to a common, run of the mill problem. It wasn’t as if the world was crying out for another Todo app but the developer(s) turned it into something really interesting, with fantastic visuals and decent UX.
I would chalk this up partly to both iOS’s great animation framework and the fact that for the first time developers had real power at their fingertips. It was the golden age.
Somewhere along the line, creative people everywhere seemed content to copy + paste whatever <insert some brand> was doing and the whole thing became derivative. The Clears of the world disappeared and apps became monotonous and boring. The golden age was over.
Flutter is super well equipped to provide you with the tools to do these types of fun designs. It also reduces (or eliminates) the complexity of having to deal with multiple, platform dependent animation/graphics/drawing/etc frameworks to implement your custom vision. Flutter is bringing old school mobile cool back!
My challenge to every Flutter developer is to use the frameworks provided to make something interesting. Put your stamp on it. If you use Option 1, 2, 3 or 4 (or a combination of the options) that’s fine. Use whatever options suit you. Just don’t feel like you have to make your app to any particular set of rules. They don’t exist (other than anything explicitly in any app store guidelines — which falls outside of this conversation).
Also, just because Apple or Google or Some popular app or whoever did it doesn’t mean you should. It doesn’t even make them right (or wrong). In the same way that you wouldn’t just copy + paste from StackOverflow (you wouldn’t, would you …) you shouldn’t be copy + pasting you application designs either.
Use the freedom Flutter provides to break free of the restrictive paradigms and thought patterns of old and get creative, damn it.