
When I looked at Tauri last week, I was asked how it compares with other similar app-building projects. Flutter is more of a platform and uses the Dart language, but I think with Tauri supporting mobile builds it might be time to look at where Flutter is right now.
Flutter is “an open source framework by Google for building beautiful, natively compiled, multiplatform applications from a single codebase.” It can compile down to ARM for full mobile support. It focuses on adaptive control of the screen.
Their playpen is called Dartpad and you can look at Dart (the logic code) and Flutter (the widget model) examples. Initially, I would assume that in the same way you can make calls to Rust within the web view in Tauri, you can make calls to Dart while in Flutter. Obviously one has to balance that unlike JavaScript and Rust, the two Google languages will have less general use. But Dart and Flutter fit together smoothly as they are fully integrated.
This week I won’t hit the “Get started” button, but will drill down into the Sunflower example, as it summarizes perfectly what Flutter is offering. You can just run it directly from the link, which loads it into Dartpad.
The 250 seeds fly from the center to the circumference, or the other way around, reacting to the slider. So some are in the middle, the rest on the edge. It is clear there is some animation as the seeds seem to float serenely.
So from a design point of view, we have three models to consider. There is the structural model (where things are in the app and on-screen), the mechanical model (how it works logically) and the interaction model (responding to events).
Structurally, we have the title “Sunflower” at the top; we have the sunflower in the middle, composed of a dotted circle of seeds and the seeds in the center. Then we have the slider at the bottom with the text showing the number of seeds in the center (from a solitary seed at the left end to all 250 as we slide to the right end).
We know we will need math to calculate the position of the seeds on the circle, and their trajectory from and to the middle.
While there are a few ways we could represent this, it would seem reasonable to have an object for each seed, representing its position, and maybe its trajectory. Then we need an object to represent the sunflower’s state. And we vaguely understand that the slider will be some form of built-in control.
OK, let’s now take a look at the basic class outlines from the code on the left side of the Dartpad. As long as you are familiar with classes, objects and JSON layout, there is nothing weird in the code. In fact, if you’ve used a CSS framework like Bootstrap, you should feel at home.
import 'dart:math' as math; import 'package:flutter/material.dart'; const int maxSeeds = 250; void main() { runApp(const Sunflower()); } class Sunflower extends StatefulWidget { ... } class _SunflowerState extends State<Sunflower> { ... } class SunflowerWidget extends StatelessWidget { ... } class Dot extends StatelessWidget { ... }
We see a bit of boilerplate with a main function running the app. We see that the Sunflower class inherits from StatefulWidget, and this class seems to also have the responsibility to hold everything for the app, as it is passed into the runApp method.
We see what looks like an internal State model for Sunflower, and a class for the SunflowerWidget (which is a stateless widget), and another stateless widget for the Dot (the seeds). It isn’t immediately clear how the responsibilities are divided at this stage. Note the maxSeeds value is set to 250.
So let’s pick the code apart like Lego, searching for the simplest elements we know must be present. First of all, we noted that the app has the title ‘Sunflower’. Where is that?
class _SunflowerState extends State<Sunflower> { int seeds = maxSeeds ~/ 2; @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( brightness: Brightness.dark, appBarTheme: const AppBarTheme(elevation: 2), ), debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: const Text('Sunflower'), ), ...
So we see that the _SunflowerState class is actually setting up (or build
ing) the app, and the AppBar contains a title, built of a Text object containing the title we recognized. This is within a Scaffold object.
The next simplest thing we know is that there is a slider. Where is that? Well, that is defined immediately after the AppBar within the body of the scaffold, within a Column object, as the child of a SizedBox:
... body: Center( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: SunflowerWidget(seeds), ), const SizedBox(height: 20), Text('Showing ${seeds.round()} seeds'), SizedBox( width: 300, child: Slider( min: 1, max: maxSeeds.toDouble(), value: seeds.toDouble(), onChanged: (val) { setState(() => seeds = val.round()); }, ), ), ...
We see that the seeds variable, defined in the first list above, is actually set to half the maxSeeds — and indeed when you run the app it starts with half the seeds in the middle, and half on the circumference.
In fact the line…
int seeds = maxSeeds ~/ 2;
…has the only explicitly weird thing in the code — a truncating division operator to round off the result of dividing by 2.
The Slider object itself maps its minimum and maximum values from 1 to the maxSeeds value. Its start position or value is set to the seeds variable. We see that the text above the slider is just a Text element using that seed value. And we now know something else — this code must be re-evaluated to work. And that is clearly done from the onChange event listener, which resets the value of seeds based on the slider’s position mapping values. If you run with a maxSeeds of 500 instead of 250, you see exactly what you expect.
Now we know there must be some maths. Where is that?
... class SunflowerWidget extends StatelessWidget { static const tau = math.pi * 2; static const scaleFactor = 1 / 40; static const size = 600.0; static final phi = (math.sqrt(5) + 1) / 2; static final rng = math.Random(); final int seeds; const SunflowerWidget(this.seeds, {super.key}); @override Widget build(BuildContext context) { final seedWidgets = <Widget>[]; for (var i = 0; i < seeds; i++) { final theta = i * tau / phi; final r = math.sqrt(i) * scaleFactor; seedWidgets.add(AnimatedAlign( key: ValueKey(i), duration: Duration(milliseconds: rng.nextInt(500) + 250), curve: Curves.easeInOut, alignment: Alignment(r * math.cos(theta), -1 * r * math.sin(theta)), child: const Dot(true), )); } ...
If you know the equation for the circumference of a circle, but are not sure what “tau” has to do with it, check this out. But our only job here is to see where the maths is done. We can also see that we create a Dot object (the seed represented graphically) for each seed with a simple for
loop. And the Dots are clearly held in the seedWidgets array. You can also see the trappings of the animation settings, including the path taken and time taken — if you have done any animation work you will recognize the easing value.
Conclusion
Hopefully, you can see from this post how Flutter compares with Tauri. Clearly the Dart language works within the widget Flutter models very tightly, to enable far greater control of what is on screen. We can tell a lot from the imports; the app only required the Dart math package and the Flutter materials for the widgets. We are being asked to think in terms of widgets — because the widgets are very much first-class objects, and the app is built around their interaction. We set up the initial conditions of the widget, and how they respond to change. The default behavior can be overridden to get what we need.
Without further examination, we can see that Flutter is giving us very tight control of what is on screen, very much like a UI framework. If this is what you need, Google has you covered here.
The post Introduction to Flutter — How Does It Compare to Tauri? appeared first on The New Stack.
Flutter gives you tight control of what is on screen, very much like a UI framework. If this is what you need, Google has you covered.