Flutter has one small difference that makes an incredible impact.
Other frameworks have a UI model that maps to native controls. Flutter has no native controls. Instead they have a UI model that is drawn on a Skia Canvas.
Here is why this approach offers many benefits.
No Native Controls
Flutter doesn’t use Native controls. Flutter has Widgets, that contain properties, methods, events and Skia drawing code.
- No native control to UI model translation code.
- An entire layer of potential bugs, errors and code mapping the UI model to the native control no longer exists.
- You can have native look and feel or not.
- Choose a widget that looks the same on all platforms.
- Choose a Cupertino (iOS) Widget or Material (Android) Widget if you want it to look native.
- Customize without restriction.
- You don’t need to wait the platform to support a control or particular look & style, you can code it yourself.
- Draw or add functionality to any widget you want.
- You don’t have to battle the platform to make a control look how you want it to.
- Improved speed.
- The canvas draw is locked at 60fps.
- Complex layouts and animations can be performed much easier.
- What about accessibility?
- Flutter takes care of this with accessibility widgets, that allows you to annotate the widget tree, so it can be read by screen readers and search engines.
- What about native behavior?
- Natively themed Widgets behave in a similar manner to native controls. If they don’t, you can customize or create a new widget to suit your requirements.
The design landscape is changing. Some UI/UX designers want a very familiar native experience, others want a branded experience. Either way, Flutter can accommodate these requests.
You focus on how your app behaves and looks, not how each platform works.
Reduced Cognitive Load
Without the need to understand how native controls differ among platforms, you are now free to focus purely on your app, Widgets and their customization.
You no longer need to:
- Understand what each platforms native capabilities are.
- Know what capabilities your cross platform framework has mapped and what they haven’t.
- Understand any workarounds or modifications the cross platform framework might have done, while interacting with native controls.
When you want to add a new feature, you add it to your app, without having to implement it on every platform.
The code for your app is all written in Dart, and runs on all supported platforms. The only code that can’t be shared is native code when calling native APIs. Though this is the same as any other cross platform framework.
Each Flutter app runs off a native shell. This can be a standard Android or iOS project, using Java/Kotlin or Obj-C/Swift.
- You can add native packages directly to these projects.
- Create a Platform Channel to call methods in your native projects.
- You create a channel on each platform, e.g. Called MyChannel.
- You then create a method that returns a value in each native platform, e.g. MyMethod.
- Then you call the channel and method name in your Dart code, it runs the native code and returns the result.
- Access to all existing native SDKs and plugins, without waiting for any cross platform framework updates.
- Use code samples you find for the native platform, without having to convert to another language.
Having to know different languages and serialize/deserialize between these methods to make a native API call, is not as good as some other framework solutions. But considering the majority of your app will be built in Dart, it isn’t likely to have a large impact.
A dart project starts with a simple page and page state. The UI is immutable, hence when you want to update the UI, you can call
setState and the UI is rebuilt with new values, and sent for rendering.
This simple setup, allows you to choose whatever architecture you want. If you want to setup Redux, Rx, Elm, even MVVM, it is possible. It allows you to choose the best path for your application.