directory

I will write a column on The nuggets about the basic process of Flutter mastery from the beginning to the relatively proficient. I will update my blog 1-2 times a week!

  • Flutter- Why do so many companies love Flutter

  • Learn about Flutter — Dart knowledge in 5 minutes

  • Learn about the Flutter project from here

  • Flutter started writing projects here

  • This makes it much easier to see the Flutter foundation and layout

  • How is rolling implemented in the Flutter project?

preface

Learn about the basic structure of the Flutter project from our previous blog post and the code that Android Studio created for the project! This blog will continue to explore the simple use of Flutter in the project, using two examples

  1. How does Flutter present list information? And how to optimize the presentation? Use of StatelessWidget
  2. Add functionality through buttons — Use of Statefulwidget
  3. Statefulwidget lifecycle description

The purpose of this article is to give you a good grasp of Flutter and StatefulWidget usage. Hopefully, you can learn about Flutter in one or two months, and you will surely have a good development level! 【 Write, Write, write 】

If you are interested in cross-platform technology and native technology, welcome to praise and attention, common progress is the goal!! 支那

StatelessWidget implementation list

2.1 Problems and Requirements

There is a requirement to display a scrollable static list. Let’s take a look at the final display:

2.2 analysis

2.2.1 Custom Widgets

In this case, it is clear that a product presentation is a large Widget that contains the following widgets:

  • Title Widget: Done using a Text Widget;

  • Described Widget: Done using a Text Widget;

  • Image Widget: Done using an Image Widget; In addition, the title, description, and image of the three display widgets are different, so let the Parent Widget determine the content

  • Create three member variables to hold the data passed in by the parent Widget

The code is as follows:

class ZXYHomeProductItem extends StatelessWidget { final String title; final String desc; final String imageURL; ZXYHomeProductItem(this.title, this.desc, this.imageURL); @override Widget build(BuildContext context) { return Column( children: [ Text(title, style: TextStyle(fontSize: 24)), Text(desc, style: TextStyle(fontSize: 18)), Image.network(imageURL) ], ); }}Copy the code

2.2.2 List Data Display

Now you can create three productitems for display

  • A Column is used in ZXYHomeContent because the three ZXYHomeProductItem created are aligned vertically.

  • MyApp is much the same as the last blog post

The following code

import 'package:flutter/material.dart'; main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: ZXYHomePage(), ); } } class ZXYHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(" product list "),), body: ZXYHomeContent(),); } } class ZXYHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(" product list "),), body: ZXYHomeContent(),); } } class ZXYHomeContent extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: <Widget>[ ZXYHomeProductItem("Apple1", "Macbook Product1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"), ZXYHomeProductItem("Apple2", "Macbook Product2", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imm9u5zj30u00k0adf.jpg"), ZXYHomeProductItem("Apple3", "Macbook Product3", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imqlouhj30u00k00v0.jpg"), ], ); }}Copy the code

2.2.3 Display of running code interface

2.2.4 Problem Analysis

  • Error message: Yellow zebra crossing appears below
  • In the Flutter layout, content cannot go beyond the screen. When it does, it does not automatically scroll, indicating an error

How to solve this problem?

  • Change Column to ListView
  • ListView can make its child widgets look like scrolling

The code is as follows:

class ZXYHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        ZXYHomeProductItem("Apple1", "Macbook Product1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
        ZXYHomeProductItem("Apple1", "Macbook Product1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
        ZXYHomeProductItem("Apple1", "Macbook Product1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
      ],
    );
  }
}
Copy the code

2.2.5 Interface effect after modification

The above effect is roughly realized, but there are still more details to be adjusted. Let’s start working on it

2.3 Adjustment of case details

2.3.1 Overall interface margin

What if you want the entire content to be at some distance from the edge of the screen?

  • You need another Widget: Padding, which has a Padding property to set the margin size,

    padding: EdgeInsets.all(12),

2.3.2 Margin and border inside the product

What if you want to add an inner margin to all items, with borders?

  • You can use the Widget of a Container, which has the Padding property, and you can set the border using decoration
  • This will be explained later in the Container.

2.3.3 Spacing of text and pictures

What if you want to add some space between images and text?

  • Method 1: Add an upward or downward inner margin to the image or text;
  • Method 2: Use the SizeBox Widget and set a height property to increase the distance.

2.4 Final code [Implementation requirements]

import 'package:flutter/material.dart'; main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HYHomePage(), ); } } class HYHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(" product list "),), body: HYHomeContent(),); } } class HYHomeContent extends StatelessWidget { @override Widget build(BuildContext context) { return ListView( children: <Widget>[ HYHomeProductItem("Apple1", "Macbook1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"), SizedBox(height: 6,), HYHomeProductItem("Apple2", "Macbook2", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imm9u5zj30u00k0adf.jpg"), SizedBox(height: 6,), HYHomeProductItem("Apple3", "Macbook2", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imqlouhj30u00k00v0.jpg"), ], ); } } class HYHomeProductItem extends StatelessWidget { final String title; final String desc; final String imageURL; final style1 = TextStyle(fontSize: 25, color: Colors.orange); final style2 = TextStyle(fontSize: 20, color: Colors.green); HYHomeProductItem(this.title, this.desc, this.imageURL); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(12), decoration: BoxDecoration(border: border. All (width: 5, // set the border width color: color.pink // set the border color), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ Text(title, style: style1), ], ), SizedBox(height: 8), Text(desc, style: style2), SizedBox(height: 8), Image.network(imageURL) ], ), ); }}Copy the code

Statefulwidget implements button addition

3.1 Problems and requirements

There is a requirement to show one

  • + button click the number to add 1;

  • – Click the button to decrease the number by 1;

Let’s take a look at the final presentation of the case:

3.2 know StatefulWidget

In development, the data presented in some Widget cases is not a constant layer:

  • For example, in the counter case of the Flutter default application, when the + sign button is clicked, the number displayed should be +1.

  • For example, in development, the data changes when you do a pull-down refresh and a pull-up load more;

The StatelessWidget is usually used to show what data is fixed, and if the data can change, use the StatefulWidget.

3.2.1 StatefulWidget introduction

If you have read the create Flutter sample application, you will see that you are creating a StatefulWidget application.

Why StatefulWidget?

  • Because in the sample code, the data displayed on the interface changes when the button is clicked;

  • At this point, you need a variable to record the current state and display that variable on a Text Widget;

  • And every time a variable changes, the content displayed on the corresponding Text changes as well;

However, there is one problem. I mentioned earlier that data defined in widgets is immutable and must be defined as final. Why?

  • This time, Because Flutter is designed to rebuild the entire Widget if the data displayed in it changes;

  • The next section explains how a Flutter renders. A Flutter uses some mechanism to specify that the member variables defined ina Widget must be final;

How does Flutter ensure that data defined in widgets during development is always final?

Take a look at the source code for the Widget

@immutable abstract class Widget extends DiagnosticableTree { // ... Omit code}Copy the code

The key point here is that @immutable is, in fact, officially stated: any class or subclass indicated by the @immutable annotation must be immutable

Conclusion: The data defined into the Widget must be immutable and needs to be decorated with finalCopy the code

3.2.2 How do I Store Widget Status?

Since widgets are immutable, how do statefulwidgets store mutable state?

  • The StatelessWidget doesn’t matter because the data in it is usually defined and left unmodified.

  • But statefulWidgets need to be changed statically. How do you do that?

Flutter designs the StatefulWidget into two classes. This means that you must create two classes when creating a StatefulWidget:

  • A class inherits from StatefulWidget as part of the Widget tree;

  • A class inherits from State to record the changing State of statefulWidgets and build new widgets based on the changing State.

To create a StatefulWidget, you typically do this:

  • When Flutter builds the Widget Tree, it gets an instance of State, and it calls the Build method to get the widgets that StatefulWidget wants to build.

  • Then you can store the state you need to save in MyState because it is mutable;

The code is as follows:

Class ZXYStatefulWidget extends StatefulWidget {@override State<StatefulWidget> createState() {// The State to be created returns ZXYState(); }}Copy the code

Ponder: Why should Flutter be designed this way?

This is because in Flutter, widgets need to be rebuilt whenever data changes.Copy the code

3.3 analysis

3.3.1 Case effect and analysis

The case effect and layout are as follows:

  • Column widget: Used before, when there is a vertical layout;

  • Row widget: Used before, when laying out horizontally;

  • RaiseButton widget: You can create a button and one of the onPress properties is passed in a callback function that is called back when the button is clicked

3.3.2 rainfall distribution on 10-12 create StatefulWidget

Because the number changes when the button is clicked, you need to use a StatefulWidget, so you need to create two classes;

  • ZXYHomeContent inherits from StatefulWidget, which implements the createState method.

  • _ZXYHomeContentState inherits from State, which implements the build method and can define some member variables;

The code is as follows:

// State is added _: The state class simply extends StatefulWidget {final String Message; ZXYHomeContent(this.message); @override State<StatefulWidget> createState() { return _ZXYHomeContentState(); }} /** * Why should the build method of the StatefulWidget be placed in State when Flutter is designed * 1. Build widgets are dependent on variables in State * 2. During the operation of Flutter: * Widgets are constantly destroyed and created * When our own state changes, Does not want to re-state a new State */ class _ZXYHomeContentState extends State<ZXYHomeContent> {int _counter = 0; @override Widget build(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment center, the children: "Widget > [Text (" the current count $_counter" style: TextStyle (fontSize: 25),), Text(" message :${widget.message}")],),); }}Copy the code

3.3.3 Button layout and button monitoring status

Widget _getButtons() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        RaisedButton(
          child: Text("+", style: TextStyle(fontSize: 20, color: Colors.white),),
          color: Colors.pink,
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
        ),
        RaisedButton(
            child: Text("-", style: TextStyle(fontSize: 20, color: Colors.white),),
            color: Colors.purple,
            onPressed: () {
              setState(() {
                _counter--;
              });
            }
        ),
      ],
    );
  }
Copy the code

3.4 Final code [Implementation requirements]

import 'package:flutter/material.dart'; main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: ZXYHomePage(), ); } } class ZXYHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(" counter project "),), body: ZXYHomeContent(" hello, ZXYHomeContent "),); }} //Widget is not added _: exposed to others, add _ for own use // State is added _: The state class simply extends StatefulWidget {final String Message; ZXYHomeContent(this.message); @override State<StatefulWidget> createState() { return _ZXYHomeContentState(); }} /** * Why should the build method of the StatefulWidget be placed in State when Flutter is designed * 1. Build widgets are dependent on variables in State * 2. During the operation of Flutter: * Widgets are constantly destroyed and created * When our own state changes, Does not want to re-state a new State */ class _ZXYHomeContentState extends State<ZXYHomeContent> {int _counter = 0; @override Widget build(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment center, the children: "Widget > [_getButtons (), Text (" the current count $_counter" style: TextStyle (fontSize: 25),), Text(" message :${widget.message}")],),); } Widget _getButtons() { return Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( child: Text("+", style: TextStyle(fontSize: 20, color: Colors.white),), color: Colors.pink, onPressed: () { setState(() { _counter++; }); }, ), RaisedButton( child: Text("-", style: TextStyle(fontSize: 20, color: Colors.white),), color: Colors.purple, onPressed: () { setState(() { _counter--; }); } ), ], ); }}Copy the code

Through the above two small cases, you are familiar with the contents of the StatelessWidget and StatefulWidget. You can also realize the small list function display and state change requirements. Write! Write!!!!!!

Now that I’ve covered the StatelessWidget and ****StatefulWidget, let’s take a look at the life cycle of the StatefulWidget.

StatefulWidget life cycle

4.1 Understanding the Flutter lifecycle

What is the life cycle?

  • Client development: iOS development needs to know the entire process of UIViewController from creation to destruction, Android development needs to know the entire process of Activity from creation to destruction. To accomplish different operations in different lifecycle methods;

  • Front-end development: Components in Vue and React development also have their own life cycle, in different life cycle can do different operations;

The lifecycle of a Flutter widget:

  • A StatelessWidget can be built by calling the build method and passing in values directly from the parent Widget.

  • Statefulwidgets need to manage their data by State, and also monitor State changes to determine whether to rebuild the entire Widget.

So, we’ll focus on the life cycle of a StatefulWidget, which is its entire process from creation to destruction.

4.2 StatefulWidget lifecycle

The StatefulWidget itself consists of two classes: StatefulWidget and State, which are analyzed separately

First, execute the relevant methods in the StatefulWidget:

  1. Execute the StatefulWidget’s Constructor to create the StatefulWidget;

  2. Execute the createState method of the StatefulWidget to create a State object that maintains the StatefulWidget.

Second, when createState is called to create the State object, the related methods of the State class are executed:

  1. Execute the Constructor of the State class to create the State object;

  2. InitState, where we usually do some data initialization or maybe send a network request; This method overrides the parent class. Super must be called because something else is going on in the parent class.

  3. Execute the didChangeDependencies method, which is called in two cases: when initState is called, and when dependent data from other objects changes.

  4. Flutter executes the build method to see which widgets need to be rendered for the current Widget.

  5. If the current Widget is no longer in use, dispose is called to destroy it.

  6. Manually calling the setState method will re-call the Build method based on the latest state (data) to build the corresponding Widgets.

  7. The didUpdateWidget method is called when the rebuild is triggered by the parent Widget.

4.3 Code verification and printing

To demonstrate this in 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 (title: Text("Flutter life cycle "),), body: ZXYHomeBody(),); } } class ZXYHomeBody extends StatelessWidget { @override Widget build(BuildContext context) { print("HomeBody build"); return ZXYCounterWidget(); }} class ZXYCounterWidget extends StatefulWidget {ZXYCounterWidget() {print(" Implements the constructor of the ZXYCounterWidget "); } @override State<StatefulWidget> createState() {print(" execute the createState method of ZXYCounterWidget "); // The State to be created returns ZXYCounterState(); } } class ZXYCounterState extends State<ZXYCounterWidget> { int counter = 0; ZXYCounterState() {print(" execute ZXYCounterState constructor "); } @override void initState() { super.initState(); Print (" Execute ZXYCounterState init method "); } @override void didChangeDependencies() { // TODO: implement didChangeDependencies super.didChangeDependencies(); Print (" Execute the didChangeDependencies method of ZXYCounterState "); } @override Widget build(BuildContext context) {print(" execute build method that executes ZXYCounterState "); 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(ZXYCounterWidget oldWidget) { super.didUpdateWidget(oldWidget); Print (" Execute ZXYCounterState's didUpdateWidget method "); } @override void dispose() { super.dispose(); Print (" Execute ZXYCounterState dispose method "); }}Copy the code

The printing result is as follows (the picture below is the printing of the project for the first time)

When we change the state, manually executing the setState method prints the following result:

Pay attention to the point

When we run the program again, look at the print

Note: Flutter builds all its components twice (check GitHub, Stack Overflow)

conclusion

This article introduces how Flutter displays list information to familiarize you with statelessWidgets. The use of Statefulwidget in your project is illustrated by the ability to self-add through buttons; This leads to the life cycle of Statefulwidget.

Through the above three points, you can write simple list presentation and interaction, you can write the above Demo example by hand! I believe that through the above examples and further progress, you can deepen your understanding and feeling of the Flutter project.

Thank you for your praise and attention to me, common progress, mutual encouragement!!