It has been a long time since Google released Flutter, and it is a new technology. So should we learn Flutter or learn Flutter? Don’t ask me. I don’t know how much the hell I have to learn in this life. In fact, the emergence of new technology also means that the old technology will become obsolete, and you will have a crisis of unemployment. In a word: you never know which will come first, the unexpected or the pleasant surprise

Environment set up

The installation of Flutter is not demonstrated here, but can be learned from the following websites.

  • Flutter website
  • Because Chinese website
  • Flutter community

These sites also offer a wealth of Flutter learning materials

The first application of Flutter

After creating a Flutter application, we can see the following demo code. (The notes are personal translation, please understand if there are incorrect)

import 'package:flutter/material.dart';

// The application starts
void main(a) => runApp(MyApp());

class MyApp extends StatelessWidget {
  // The root Widget for this App
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo'./ / application name
      theme: ThemeData(
        // The theme of this application
        //
        // You run the application with "flutter run" and you will see a blue ToolBar.
        // You can also change the value of primarySwatch below from colors.blue to colors.green.
        // Then perform "hot reload", you can see that the counter is not restored to its original state of 0, and the application is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // We can see that the Widget for MyHomePage is the first page of the app, and that it is stateful.
  // This means that the fields in the State object defined below can affect the display of the application.

 // This class is the configuration class for this state. It holds the title value provided by its parent class.
 // Used by methods that create state, always marked as "final" ina Widget subclass

  final String title;

  @override
  _MyHomePageState createState(a) => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter(a) {
    setState(() {
      // Call setState to tell the Flutter framework that some state has changed.
      // Let the following build method return Widget to display the updated content. Of course, if we don't have a callback
      // With setState, the build method will not be called and no updates will be displayed.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is called every time setState is called, such as the _incrementCounter method above.
    //
    // The Flutter framework is optimized, so its re-run build method is very fast and only needs to be used
    // Run the content you need to update, without having to separate all widgets instances.
    return Scaffold(
      appBar: AppBar(
        // We can use the values created in the app.build method and assign them
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout Widget that provides a child and specifies that it should only be in the Center of its parent class
        child: Column(
          // Column is also a layout Widget that has a series of child layouts that are vertical.
          // By default, Column adjusts its own size to fit the horizontal size of its children.
          //
          // Call "Debug painting" to see the wireframe for each widget
          //
          // Column has a number of attributes to control its size and the position of its children, using mainAxisAlignment
          // Let the child layout content be arranged vertically.
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.); }}Copy the code

Run the Flutter

I used the Flutter application created by Android Studio. You can see the compilation screen for Flutter as shown below

  • Click on theRun(that’s the green triangle) then we can see the following result:

  • Click on the blue"+"As you can see, the middle number keeps increasing, so demo gives me an implementation of a simple counter

Analysis of the Demo

We know from the official website that Flutter is encoded in Dart language. Do we need to learn and master this language alone? In my opinion, it is not necessary, because the process of learning a new language alone is very boring. We can learn it from the Demo, which is more efficient. So let’s analyze what the above example tells us.

import 'package:flutter/material.dart';

void main(a) => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}Copy the code

From the above code we know:

  • First, I imported a file calledmaterialthedartFile.
  • Through amain()Method calledMyAppClass of.
  • This MyApp is the entry point to this app. (according torunAppKnown)

There are questions about a Flutter:

  • Why importmaterialWhere are the files? Encounter such a place, we can go to the official website to check the information, the official website to answer as follows:

Flutter provides many widgets to help you build applications that follow Material Design. The Material application starts with the MaterialApp Widget, which creates some useful widgets at the root of the application, including a Navigator that manages the widget stack (page routing stack) identified by strings. Navigator allows your application to move smoothly between pages. Whether or not to use the MaterialApp is entirely optional, but it is a good practice to use it.


In order to provide developers with the material design style that has been implemented, we can enter (Windows Ctrl + left mouse button, Mac Command+ left mouse button) The material. Dart source code, can be found as follows:

library material;

export 'src/material/about.dart';
export 'src/material/animated_icons.dart'; .// Many, I won't take up too much space here
export 'widgets.dart';
Copy the code

We know there are plenty of widgets available, but where are they? Dart file, which looks like this:

export 'src/widgets/animated_cross_fade.dart'; . export'src/widgets/framework.dart'; . export'src/widgets/will_pop_scope.dart';
Copy the code

Also a different DART file, we go to the first animated_cross_fade:

class AnimatedCrossFade extends StatefulWidget {
/// Creates a cross-fade animation widget.. }Copy the code

As you can see from the comment, this is a Widget with a fade in and fade out animation. This Widget inherits from the StatefulWidget

abstract class StatelessWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatelessWidget({ Key key }) : super(key: key);

  /// Creates a [StatelessElement] to manage this widget's location in the tree.
  ///
  /// It is uncommon for subclasses to override this method.
  @override
  StatelessElement createElement(a) => StatelessElement(this);

  @protected
  Widget build(BuildContext context);
}


abstract class StatefulWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatefulWidget({ Key key }) : super(key: key);

  /// Creates a [StatefulElement] to manage this widget's location in the tree.
  ///
  /// It is uncommon for subclasses to override this method.
  @override
  StatefulElement createElement(a) => StatefulElement(this);
  @protected
  State createState(a);
}
Copy the code

The StatelessWidget that MyApp inherits from the Demo code is also here, but MyHomePage inherits from the StatefulWidget. Why? Which brings us to the second question:

  • StatelessWidgetandStatefulWidgetWhat is the difference between?

Statefulwidgets can have states that can change during the widget’s life cycle, whereas StatelessWidgets are immutable. The StatefulWidget consists of at least two classes:

  • A StatefulWidget class.
  • A State class; The StatefulWidget class itself is immutable, but the State held in the State class may change during the widget’s life cycle.

StatelessWidget is used in scenarios where no state needs to be maintained. It typically builds the UI by nesting other widgets in the build method, recursively building its nested widgets during the build process


That’s why MyApp inherits from the StatelessWidget and MyHomePage inherits from the StatefulWidget:

  • MyApp does not need to change the state, just nested a MyHomePageWidget
  • And myFile inheritsStatefulWidgetHere’s why: By clicking+To increase the number size changes the display state, so inheritance is requiredStatefulWidget.

Analyze execution mode

If we go back to the build method of MyApp, we can see that it returns a Widget of the MaterialApp. As mentioned earlier, the Material Design application starts with the MaterialApp Widget, so it returns a MaterialApp

return MaterialApp(
      title: 'Flutter Demo'./ / application name
      theme: ThemeData(
        primarySwatch: Colors.blue, / / theme color
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'), / / home page
    );
Copy the code

Since counting is a mutable update state, we need two classes to implement it:

  • One inherited fromStatefulWidgetIt’s oursMyHomePage
  • One inherited fromStateTo maintain this state, which is ours_MyHomePageState
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // We can see that the Widget for MyHomePage is the first page of the app, and that it is stateful.
  // This means that the fields in the State object defined below can affect the display of the application.

 // This class is the configuration class for this state. It holds the title value provided by its parent class.
 // Used by methods that create state, always marked as "final" ina Widget subclass

  final String title;

  @override
  _MyHomePageState createState(a) => _MyHomePageState();
}
Copy the code

MyHomePage doesn’t have much in it:

  • The title value is passed in through the constructor
  • throughcreateStateReturns a_MyHomePageStateStateful ofState

Here we know that the operation on the data must actually be in _MyHomePageState:

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter(a) {
    setState(() {
      // Call setState to tell the Flutter framework that some state has changed.
      // Let the following build method return Widget to display the updated content. Of course, if we don't have a callback
      // With setState, the build method will not be called and no updates will be displayed.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is called every time setState is called, such as the _incrementCounter method above.
    //
    // The Flutter framework is optimized, so its re-run build method is very fast and only needs to be used
    // Run the content you need to update, without having to separate all widgets instances.
    return Scaffold(
      appBar: AppBar(
        // We can use the values created in the app.build method and assign them
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout Widget that provides a child and specifies that it should only be in the Center of its parent class
        child: Column(
          // Column is also a layout Widget that has a series of child layouts that are vertical.
          // By default, Column adjusts its own size to fit the horizontal size of its children.
          //
          // Call "Debug painting" to see the wireframe for each widget
          //
          // Column has a number of attributes to control its size and the position of its children, using mainAxisAlignment
          // Let the child layout content be arranged vertically.
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
Copy the code

You can see that there are two methods provided here: build and _incrementCounter. We already know that the build method in a Widget typically returns a page layout.

The implementation of _incrementCounter is simple: You increment _counter with setState, but one thing to note here is that you have to use setState to change the state, because if you don’t call setState nothing will change, even if you increment _counter. (Try it yourself)

We can see from the comment that the build method is called every time the setState is updated. We can verify this by adding a line of printed code to the build method:

@override
  Widget build(BuildContext context) {
    print("build again");
    returnScaffold( ... ) ;Copy the code

The build method is called every time + is clicked, which raises the question: does this update every time affect new energy?


The Flutter framework is optimized for quick restart and only needs to run the content you need to update. There is no need to rebuild all the widgets instances separately.


So you don’t have to worry about the performance impact of executing the build method every time.

We know from the overall layout that build returns a Scaffold widget:

class Scaffold extends StatefulWidget {
  /// Creates a visual scaffold for material design widgets.
  const Scaffold({
    Key key,
    this.appBar,
    this.body,
    this.floatingActionButton,
    this.floatingActionButtonLocation,
    this.floatingActionButtonAnimator,
    this.persistentFooterButtons,
    this.drawer,
    this.endDrawer,
    this.bottomNavigationBar,
    this.bottomSheet,
    this.backgroundColor,
    this.resizeToAvoidBottomPadding,
    this.resizeToAvoidBottomInset,
    this.primary = true.this.extendBody = false.this.drawerDragStartBehavior = DragStartBehavior.down,
  }) : assert(primary ! =null).assert(extendBody ! =null).assert(drawerDragStartBehavior ! =null).super(key: key);

Copy the code

As you can see, this also inherits from the StatefulWidget. There are a number of initial values that can be set, three of which are used here:

  • AppBar – Layout title bar
  • Body – Content display area
  • FloatingActionButton – Float button
return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
Copy the code

Assign the title carried from MyApp to the title of appBar so that it appears at the top of the screen. The body uses a Center layout so that its child (also a widget) can only be displayed in the current Center position.

class Center extends Align {
  /// Creates a widget that centers its child.
  const Center({ Key key, double widthFactor, double heightFactor, Widget child })
    : super(key: key, widthFactor: widthFactor, heightFactor: heightFactor, child: child);
}
Copy the code

The widget returns the child of a Column. The widget is vertically aligned and has a series of subsets, so there are two Text columns, one for fixed Text and one for variable Text:

class Column extends Flex {
  Column({
    Key key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline textBaseline,
    List<Widget> children = const <Widget>[],
  }) : super(
    children: children,
    key: key,
    direction: Axis.vertical,
    mainAxisAlignment: mainAxisAlignment,
    mainAxisSize: mainAxisSize,
    crossAxisAlignment: crossAxisAlignment,
    textDirection: textDirection,
    verticalDirection: verticalDirection,
    textBaseline: textBaseline,
  );
}
Copy the code

Note that the $sign is used for variable placeholders, just as % is used in Java. Finally, we click on the event’s button floatingActionButton and use onPressed to call the _incrementCounter method to increment the count. This is the end of the whole running process.

Hot Reload

As we know at the beginning of this article, we have a Hot Reload icon. What does that mean? It means that if you update your code, instead of rerunking the whole thing, you just use this, and you can quickly redisplay what you’ve updated. Here’s an interesting thing: we hit + to show the counter to 1, and then change the theme color to green: primarySwatch: colors.green,


class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
       // Theme changes from blue to green
        primarySwatch: Colors.green,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}Copy the code

Then hit Hot Reload and our theme changed to green, but my counter still showed a 1, not a 0. This confirms the previous statement that Hot Reload only changes what needs to be changed, not everything.

conclusion

Here is a summary, I hope to help you

  • influtterMost of the available content iswidget
  • If you just want to display the content without changing the state, useStatelessWidget; This is used if a state change is involvedStatefulWidget
  • StatefulWidgetThere are two steps to the implementation: one is to create inheritanceStatefulWidgetIn the class; The other is to create inheritanceStateClass, which generally controls the entire State in State.
  • Update status must be calledsetStateMethod, or it won’t work
  • hot reloadOnly what is changed will be affected