Stateful widget of fluent (7)

Time:2020-2-1

Foreword 1: I will update some columns of flutter text tutorials in succession in the next period

Update progress:At least two articles per week;

Update location:First appeared in the public number, and the second day was updated in nuggets, thoughts and developers’ headlines.

More communication:You can add my wechat 372623326 and follow my micro blog: Code why

I hope you canHelp forward, click to seeGive me more creative power.

1、 Statefulwidget

In development, in some widget cases, the data we show is not the same at one level:

For example, for the counter case in the default program of flutter, after clicking the + button, the displayed number needs + 1;

For example, in the development process, we will perform pull-down refresh and pull-up load more, and then the data will change;

Statelesswidget is usually used to show which data is fixed and unchanging. If the data changes, we use stateful widget;

1.1. Know statefulwidget

1.1.1. Introduction to statefulwidget

If you have read the example program that we created the flutter by default, you will find that it creates a stateful widget.

Why stateful widget?

  • Because in the example code, when we click the button, the data displayed on the interface will change;
  • At this point, we need avariableTo record the current status, and then display this variable on a text widget;
  • And each timevariableWhen there is a change, the content displayed on our corresponding text will also change;

But there is a problem. I said before that the data defined in the widget is immutable and must be defined as final. Why?

  • This time, the flutter decided to rebuild the whole widget once the data displayed in the widget changed during design;
  • In the next chapter, I will explain the rendering principle of flutter, which is defined into widget through some mechanismsMember variablesMust befinal.

How can flutter ensure that the data defined in the widget in our development must be final?

Let’s look at the source code of widget:

@immutable
abstract class Widget extends DiagnosticableTree {
    //... omit code
}

Here is a very important thing @ immutable

  • We don’t seem to see this syntax in dart, which is actually aannotation, which is designed to dart’s metaprogramming, we will not talk about it here;
  • Here I will explain what @ immutable does;

In fact, @ immutable is officially explained:

  • Source: https://api.flutter.dev/flutt…
  • Explain:The class or subclass indicated by @ immutable annotation must be immutable

Stateful widget of fluent (7)

Conclusion:The data defined in the widget must be immutable and need to be decorated with final

1.1.2. How to store widget status?

Since widgets are immutable, how can stateful widgets store mutable States?

  • Statelesswidget doesn’t matter, because the data in it is usually directly defined and will not be modified after playing.
  • But statefulwidget needs to change state (which can be understood as variable). How to do this?

Flutter designs statefulwidget into two classes:

  • In other words, when you create statefulwidget, you must create two classes:
  • A class inherits from statefulwidget as part of widget tree;
  • A class inherits from state, which is used to record the state that statefulwidget will change, and build a new widget according to the state change;

To create a statefulwidget, we usually do it in the following format:

  • When flutter is building widget tree, it will getInstance of state, and it calls the build method to get the widget that statefulwidget wants to build;
  • Then, we can save the state to be saved in mystate, because it is mutable;
class MyStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    //Return the created state
    return MyState();
  }
}

class MyState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    Return < build your own widget >;
  }
}

Thinking: why should flutter be designed like this?

This is because in flutter, as long as the data changes the widget, it needs to be rebuilt

1.2. Statefulwidget case

1.2.1. Case effect and analysis

Let’s practice stateful widget through a case, which is the previous counter case, but we make some improvements in our own way.

The case effect and layout are as follows:

  • In this case, there are many layouts that are complex for us. We will learn in detail later. We suggest that you write them step by step according to my code to be familiar with the development mode of flutter;
  • Column widget: we have used it before. When there is a vertical layout, we use it;
  • Row widget: it has been used before, when we used it for horizontal layout;
  • Raisebutton widget: you can create a button with oneOnpress propertyIt’s an incomingCallback function, when the button is clicked, it is recalled;

Stateful widget of fluent (7)

1.2.2. Create statefulwidget

Let’s take a look at the code implementation:

  • Because when we click the button, the number will change, so we need to use a statefulwidget, so we need to create two classes;
  • Mycounterwidget inherits from statefulwidget, which needs to implement createstate method;
  • Mycounterstate inherits from state, which implements the build method and can define some member variables;
class MyCounterWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    //Return the created state
    return MyCounterState();
  }
}

class MyCounterState extends State<MyCounterWidget> {
  int counter = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      Child: text ("current count: $counter", style: TextStyle (fontsize: 30),),
    );
  }
}

Stateful widget of fluent (7)

1.2.3. Realize the layout of buttons

class MyCounterState extends State<MyCounterWidget> {
  int counter = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                color: Colors.redAccent,
                child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {

                },
              ),
              RaisedButton(
                color: Colors.orangeAccent,
                child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {

                },
              )
            ],
          ),
          Text ("current count: $counter", style: TextStyle (fontsize: 30),)
        ],
      ),
    );
  }
}

Stateful widget of fluent (7)

1.2.4. Button click status change

Now we need to monitor the status change and modify it when the status changesCounter variable

  • But can changing variables directly change the interface? May not.
  • This is because flutter doesn’t know that our data has changed, so we need to rebuild the widget in our interface;

How can we let flutter know that our state has changed and rebuild our widget?

  • We need to call the setstate method provided to us by default in a state;
  • We can modify our variables in the callback function;
onPressed: () {
  setState(() {
    counter++;
  });
},

In this way, the desired effect can be achieved:

Stateful widget of fluent (7)

1.3. Statefulwidget life cycle

1.3.1. Life cycle understanding

What is life cycle?

  • Client development: in IOS development, we need to know the whole process of uiviewcontroller from creation to destruction, and in Android development, we need to know the whole process of activity from creation to destruction. In order to complete different operations in different life cycle methods;
  • In front-end development: components in Vue and react development also have their own life cycle, and we can do different operations in different life cycles;

Life cycle of the flutter widget:

  • Statelesswidget can be directly passed in value by the parent widget and built by calling the build method. The whole process is very simple;
  • Stateful widget needs to manage its data through state, and monitor the change of state to decide whether to rebuild the whole widget;
  • Therefore, we mainly discuss the life cycle of statefulwidget, that is, the whole process from creation to destruction;

1.3.2. Simple version of life cycle

In this version, I will explain the common methods and callbacks. In the next version, I will explain some more complex methods and callbacks

What are the life cycle callbacks of statefulwidget? Under what circumstances are they executed respectively?

  • In the following figure, the contents of gray part are internally operated by flutter, and we do not need to set them manually;
  • The white part indicates the methods that we can monitor or call manually;

We know that statefulwidget itself consists of two classes:StatefulWidgetandState, we analyze separately

Stateful widget of fluent (7)

First, executeStatefulWidgetMethods related to:

  • 1. Execute the constructor of statefulwidget to create statefulwidget;
  • 2. Execute the createstate method of statefullwidget to create a state object to maintain statefullwidget;

Second, when calling createstate to create a state object, execute the relevant methods of the state class:

  • 1. Execute the constructor of the state class to create the state object;
  • 2. Execute initstate. We usually perform some data initialization operations in this method, or we may send network requests;

    • Note: this method is to override the method of the parent class. You must call super, because there will be some other operations in the parent class;
    • And if you read the source code, you will find an annotation here: @ mustcallsuper

Stateful widget of fluent (7)

  • 3. Execute the didchangedependencies method, which calls in two cases
    • Case 1: calling initstate will call;
    • Case 2: when some data is changed from other objects, such as the inherited widget we mentioned earlier (this will be discussed later);
  • 4. Flutter executes the build method to see which widgets our current widget needs to render;
  • 5. When the current widget is no longer used, dispose will be called to destroy it;
  • 6. Manually calling setstate method will call build method again according to the latest state (data) to build corresponding widgets;
  • 7. To execute the didupdatewidget method, when the parent widget triggers rebuild, the system will call the didupdatewidget method;

Let’s demonstrate with code:

import 'package:flutter/material.dart';

main(List<String> args) {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("HelloWorld"),
        ),
        body: HomeBody(),
      ),
    );
  }
}


class HomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("HomeBody build");
    return MyCounterWidget();
  }
}


class MyCounterWidget extends StatefulWidget {
  
  MyCounterWidget() {
    Print ("executed the construction method of mycounterwidget");
  }
  
  @override
  State<StatefulWidget> createState() {
    Print ("createstate method of mycounterwidget executed");
    //Return the created state
    return MyCounterState();
  }
}

class MyCounterState extends State<MyCounterWidget> {
  int counter = 0;
  
  MyCounterState() {
    Print ("the constructor that executes mycounterstate");
  }

  @override
  void initState() {
    super.initState();
    Print ("execute init method of mycounterstate");
  }
  
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    Print ("execute didchangedependencies method of mycounterstate");
  }

  @override
  Widget build(BuildContext context) {
    Print ("execute the build method to execute mycounterstate");
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                color: Colors.redAccent,
                child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter++;
                  });
                },
              ),
              RaisedButton(
                color: Colors.orangeAccent,
                child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter--;
                  });
                },
              )
            ],
          ),
          Text ("current count: $counter", style: TextStyle (fontsize: 30),)
        ],
      ),
    );
  }

  @override
  void didUpdateWidget(MyCounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    Print ("execute the didupdatewidget method of mycounterstate");
  }

  @override
  void dispose() {
    super.dispose();
    Print ("execute the dispose method of mycounterstate");
  }
}

The printing results are as follows:

flutter: HomeBody build
Flitter: executed the construction method of mycounterwidget
Flitter: executed the createstate method of mycounterwidget
Flitter: construction method to execute mycounterstate
Flitter: execute init method of mycounterstate
Flitter: execute didchangedependencies method of mycounterstate
Flitter: execute the build method to execute mycounterstate

//Note: flutter will build all components twice (check GitHub and stack overflow, no reason is found at present)
flutter: HomeBody build
Flitter: executed the construction method of mycounterwidget
Flitter: execute the didupdatewidget method of mycounterstate
Flitter: execute the build method to execute mycounterstate

When we change the state and manually execute the setstate method, the following results will be printed:

Flitter: execute the build method to execute mycounterstate

1.3.3. Complex version of life cycle (optional reading)

Let’s learn a few properties mentioned in the previous life cycle diagram, but they are not explained in detail

1. Mounted is an internal property of state. In fact, we can’t understand it. But if you want to know it in depth, you will understand the mechanism of state more clearly;

  • Many materials don’t mention this property, but I’ve listed it here. It’s set internally and doesn’t need to be modified manually;

Stateful widget of fluent (7)

2. Dirty state means dirty state

  • It is actually marked by the attribute of an element (we haven’t talked about the principle of flutter drawing yet);
  • Marking it as dirty will wait for the next redraw check, forcing the call to build method to build our widget;
  • (I will write a special article about the difference between stateless widget and stateful widget, and explain some selection problems in their development);

3. Clean state means clean state

  • It represents the Widget from the current build, and does not need to be re build in the next redraw check;

2、 Programming paradigm of flutter

This chapter also explains some theoretical things. It may not directly teach the knowledge of flutter, but it will have some simple ideas for you to write any code in the future;

2.1. Understanding of programming paradigm

Programming paradigmIt’s a mirage for beginners, but it’s something we follow by default in our daily developmentSome modes and methods

For example, the most familiarobject-oriented programmingIt is a programming paradigm, with which the corresponding or combined development includes: process oriented programming, functional programming, protocol oriented programming;

There are also two corresponding programming paradigms:Command programmingandDeclarative programming

  • Command programming:Imperative programming is very easy to understand, that is, step by step to the computer command, tell it what we want to do;
  • Declarative programming:Declarative programming usually describes the nature of the target, what kind of state you should depend on, and when the state of the dependency changes, we inform the target to make corresponding decisions in some ways;

The above description is too general. Let’s take a look at some specific examples;

2.2. Programming paradigm of front end

The following code hasn’t written the front end, you can take a look at it

The following code is two demo I wrote in the front-end development, which are used to modify the content of H2 tag after clicking the button:

  • Left Code:Command programming, step by step to tell the browser what I want to do;
  • Right code:Declarative programming, I just tell the H2 tag that I need to display the title. When the title changes, I can update the status automatically through some mechanisms;

Stateful widget of fluent (7)

2.3. Programming paradigm of flutter

Declarative programming has been popular since 2009 (data from Wikipedia), and it is currently used in Vue, react, swiftui including IOS, and flutter.

Now let’s develop a requirement: display a hello world, and then change it to Hello shuttle

If it’s traditional imperative programming, the pattern of developing flutter is likely to be as follows: (note that it’s imaginary pseudo code)

  • In the whole process, we need to tell flutter what it needs to do step by step;
final text = new Text();
var title = "Hello World";
text.setContent(title);

//Modify data
title = "Hello Flutter";
text.setContent(title);

In case of declarative programming, we usually maintain a set of data sets:

  • This data set may come from its own parent class, from its own state management, from inheritedwidget, and from a unified state management place;
  • In a word, we know that there is such a data set, and tell flutter where these data sets are used;
var title = "Hello World";

Text (title); // tell text that the title is displayed inside

//Data change
title = "Hello Flutter";
Setstate (() = > null); // notify rebuild widget

The above code is too simple, which may not reflect the advantages of the declarative programming of fluent, but in the future development, we are all starting according to this mode, and we will slowly experience it together;

Note: all contents start with the public number. In addition to Flutter, other technical articles will be updated. TypeScript, React, Node, uniapp, mpvue, data structure and algorithm will also update some of their own learning experiences. Welcome everyone’s attention.

Stateful widget of fluent (7)

Recommended Today

The way of database evolution

History of database development RDBMS Representatives: Oracle (commercial), MySQL (open source).Relational database (RDBMS) is the most widely used database management system. It can not only store data, but also perform complex data operations (left join, subquery, etc.).He has the following shortcomings: Cannot process unstructured data. In essence, it is a stand-alone system, which is difficult […]