catalogue
1. Introduce the apply function
2. Use Mixin to separate Method and Style
In fluent, the declarative view style code and the imperative business function code are mixed, resulting in the confusion of the structure when writing the code, making the nesting level of the code too deep, and the "nesting hell" will be written if you are not careful.
My idea is to use the Dart language mixin and extension functions to separate the view, function and style of fluent. Just like Vue, it can be clearly divided into three parts: template/script/style. Make the structure clearer and reduce nesting.
1. Introduce the apply function
First, you need to introduce an extension function called apply to all window classes (widgets):
extension ApplyExt on Widget { Widget apply(Function style){ return style.call(this); } }
Similar to Kotlin's apply. The apply function here accepts a style function as a parameter. Style is a function that takes a Widget as an input parameter and returns a Widget. In the style function, windows will be wrapped, such as Padding, SizedBox, and GestureDetector.
For example, a style function used to decorate the title text might be like this (to distinguish from the general method, the name of the style function begins with $):
Widget $title(Widget e) => Padding( padding: const EdgeInsets.all(10), child: SizedBox( height: 40, child: e, ), );
The style function is just like CSS in the Web front end, and apply can also be compared to class binding. By reducing styles to functions, styles can be separated from views and reused:
class MyPage extends StatelessWidget { const MyPage({super.key}); @override Widget build(BuildContext context) { return Column( children: [ Text("first line").apply($title), Text("second line").apply($title), Text("third line").apply($title), ], ); } }
Similarly, the style of a file can also be reused by other files in the form of style function, and even save some common style function libraries similar to css files! Like css, these style functions can be used for any widget, not limited to a certain widget!
2. Use Mixin to separate Method and Style
We also need to separate the code part of function and Style from the View. At the very least, we want to write View, Method and Style in three different "classes". But in Dart, using Mixin is more appropriate than using classes.
Dart's Mixin can write the code of functions and styles outside the class where the view is located.
Create two mixins, Method and Style, put the methods used in the view into Method and the Style functions used in Style, and finally mix Method and Style into the class where the view is located. In the build function where the view is located, you only need to write layouts such as Column and Row!
For example, a simple counter can be written as follows:
class CustomWidget extends StatefulWidget { const CustomWidget({Key? key}) : super(key: key); @override CustomWidgetState createState() => CustomWidgetState(); } //Only the layout and window are written in the build function, and Method and Style are mixed into the State class class CustomWidgetState extends State<CustomWidget> with Method,Style{ @override Widget build(BuildContext context) { return Column( children: [ const Text("Click the button below").apply($title), IconButton( icon: const Icon(Icons.add), onPressed:(){setState((){increment();});}, ).apply($button), Text(countText).apply($countText) ], ); } } //Function functions and variables used in Method mixin Method{ int _count = 0; increment(){ _count++; } String get countText => "frequency: $_count"; } //Writing Style functions in Style is like writing CSS mixin Style{ $title(e) => Padding( padding: const EdgeInsets.all(30), child: SizedBox( width: 300, child: Center( child: e, ), ) ); $button(e) => SizedBox( width: 100, height: 50, child: e, ); $countText(e) => Padding( padding: const EdgeInsets.symmetric( vertical: 30, ), child: e, ); }
We can see that the whole Flutter code is clearly divided into three parts (named with the initials B-M-S):
B: View part (Build function). All row and column layouts and window codes.
M: Method part (method blending). Methods, variables, and calculation variables used in the view.
S: Style part (style blending). All style functions used to decorate window components.
This corresponds to the three tags <template>, <script> and <style> in Vue. It can also be said that this is a more structured way of writing code.
3. Summary: BMS mode
The benefits of B-M-S mode are (B-Build, M-Method, S-Style):
- Code nesting is greatly reduced. The original view is divided into three parts. The most cumbersome styles have been incorporated into Style blending components and can be reused by the apply function. You only need to write the layout of rows and columns in the view and the initialization of the window in the build function. The rest of the styles are introduced in a way similar to the class binding in the Web front end (apply function).
- The code is more structured. The construction of a component is strictly divided into views, methods, and styles. It is not necessary to mix the function code into the view code. When designing components, you can adopt the logical sequence of view → style → method.
- There is no framework or dependency introduced, and it is completely based on Dart's original syntax. The only change is the addition of an apply function with less than 5 lines. Because it is completely based on Dart syntax, it can be easily combined and converted with general code writing, and it can also be introduced into frameworks such as Provider at any time.
Finally, provide a code template for Android Studio to implement this mode:
class $NAME$ extends StatefulWidget { const $NAME$({Key? key}) : super(key: key); @override State<$NAME$> createState() => $SNAME$(); } class $SNAME$ extends State<$NAME$> with Method,Style{ @override Widget build(BuildContext context) { //build code here. return Container($END$); } } mixin Method on State<$NAME$>{ get prop => widget; //method code here. } mixin Style on State<$NAME$>{ //style code here. } //SNAME : regularExpression(concat("_", NAME, "State"), "^__", "_")