Welcome to follow the official wechat account: FSA Full stack action 👋

1. Program entry

Generally, the main entrance to a Flutter is main.dart.

1. The nature of the interface (Widgets)

Start a Flutter interface with the runApp function in main. The Widget app received by runApp is the interface, i.e. the interface is a Widget:

main() {
  runApp(Center(
    child: Text("Hello world",
        textDirection: TextDirection.ltr,
        style: TextStyle(fontSize: 30, color: Colors.orange)),
  ));
}
Copy the code

In Flutter, all interfaces and controls are widgets

2, MaterialApp

To quickly develop a standard Material interface, The MaterialApp Widget is provided by Flutter:

import 'package:flutter/material.dart';

main() {
  // 1. RunApp function
  runApp(MaterialApp(
    / / debugShowCheckedModeBanner: false, / / control interface whether the upper right corner of the display ` debug ` hints
    home: Scaffold(
      appBar: AppBar(
        title: Text("The first Flutter program"),
      ),
      body: Center(
        child: Text(
          "Hello World",
          textDirection: TextDirection.ltr,
          style: TextStyle(fontSize: 30, color: Colors.orange),
        ),
      ),
    ),
  ));
}
Copy the code

Scaffolding is a Widget that translates as scaffolding to help developers build interfaces with appBars

Second, the State of the Widget

Flutter, everything based on widgets, divides widgets into two categories:

  • StatelessWidget: stateless Widget that determines that no state (data) changes
  • StatefulWidget: stateful Widget that has some data that needs to change during runtime

1, StatelessWidget

In the above demo, the runApp(Widget App), MaterialApp({this.home}) and Scaffold({this.body}) methods all receive the Widget type parameters and do not save the state. So you can split them into three statelessWidgets to avoid nesting hell:

This approach of extracting widgets is similar to component-development in a large front end

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, home: HomePage(), ); }}class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("The first Flutter program"), ), body: ContentBody(), ); }}class ContentBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        "Hello World",
        textDirection: TextDirection.ltr,
        style: TextStyle(fontSize: 30, color: Colors.orange), ), ); }}Copy the code

Quick template creation with State Widget in AndroidStudio:

  • Stless: Enter stless to generate the StatelessWidget
  • Stful: Type stful to generate the StatefulWidget directly

2, StatefulWidget

Flutter is declaratively developed, meaning that the interface automatically changes when a state changes, in this case the state is data. A StatefulWidget is a Widget that can be stateful. A simple example is to write a consent control:

/// State flag:
/// Stateful could not define State -> create a separate State class which was responsible for maintaining State
class ContentBody extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    returnContentBodyState(); }}/// Use the State class to hold the State
class ContentBodyState extends State<ContentBody> {
  var flag = true;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Checkbox(
            value: flag,
            onChanged: (value) {
              /// flag = value; // Invalid code will not refresh the interface
              /// The setState() method must be used to force an interface refresh
              setState(() {
                flag = value;
              });
            },
          ),
          Text("Consent agreement", style: TextStyle(fontSize: 20)),,),); }}Copy the code

Note:

  • The concept of State in Flutter is the same as that in React.
  • You can’t just modify the data, you have to call itsetState()The notification screen must be redrawn on the next frame.

3. Why can’t the State Widget itself define State?

Whether a StatelessWidget or a StatefulWidget, its parent class is a Widget.

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

Widgets have the @immutable annotation, which means that all subclasses of widgets, even if they have member attributes, must use final variables.

/// State cannot be defined in any Widget class, and class member attributes must be final
class ContentBody extends StatelessWidget {
  // IDE error: This class (or a class that this class inherits from) is marked as '@immutable', but one of more of its instance fields aren't final: ContentBody.flag

  // Error code
  // for @immutable annotated classes, member attributes must be final
  var flag = true;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Checkbox(value: flag, onChanged: (value) => flag = value),
          Text("Consent agreement", style: TextStyle(fontSize: 20)),,),); }}Copy the code

3. Comprehensive cases

1. StatelessWidget Integrated Case (List of Items)

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    returnMaterialApp( home: HomePage(), ); }}class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("List of Goods"), ), body: HomeContent(), ); }}class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Column will cross the relayoutBoundary and change to ListView
    return ListView(
      children: [
        HomeProductItem("Apple1"."Macbook1"."https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
        SizedBox(height: 6),
        HomeProductItem("Apple2"."Macbook2"."https://tva1.sinaimg.cn/large/006y8mN6gy1g72imm9u5zj30u00k0adf.jpg"),
        SizedBox(height: 6),
        HomeProductItem("Apple3"."Macbook3"."https://tva1.sinaimg.cn/large/006y8mN6gy1g72imqlouhj30u00k00v0.jpg"),]); }}class HomeProductItem 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);

  HomeProductItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(8),
      decoration: BoxDecoration(
        border: Border.all(
          width: 5.// Set the width of the border
          color: Colors.pink, // Set the color of the border
        ),
      ),
      child: Column(
        // crossAxisAlignment: CrossAxisAlignment.start,
        // crossAxisAlignment: CrossAxisAlignment.center,
        // crossAxisAlignment: CrossAxisAlignment.end,
        // crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          // Text(title, style: style1, textAlign: TextAlign.center),
          Text(title, style: style1),
          SizedBox(height: 8),
          Text(desc, style: style2),
          SizedBox(height: 8), Image.network(imageURL), ], ), ); }}Copy the code

2. Comprehensive Case of StatefulWidget (Counters)

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    returnMaterialApp( home: HomePage(), ); }}class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("title")),
      body: HomeContent("hello world")); }}/// Why is the build method of the StatefulWidget in State when Flutter is designed
/// 1.Build widgets that depend on variables in State (State/data)
/// 2.During the operation of Flutter:
/// Widgets are constantly destroyed and created
/// We don't want to create a new State when our own State changes
class HomeContent extends StatefulWidget {
  final String message;

  HomeContent(this.message);

  @override
  _HomeContentState createState() => _HomeContentState();
}

class _HomeContentState extends State<HomeContent> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _getButtons(),
          Text("Current count:$_counter", style: TextStyle(fontSize: 25)),
          Text("The message:${widget.message}")],),); } Widget _getButtons() {return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ElevatedButton(
          child: Text("+", style: TextStyle(fontSize: 20)),
          style: TextButton.styleFrom(backgroundColor: Colors.pink),
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
        ),
        ElevatedButton(
          child: Text("-", style: TextStyle(fontSize: 20)), style: TextButton.styleFrom(backgroundColor: Colors.purple), onPressed: () { setState(() { _counter--; }); },),,); }}Copy the code

4. Life cycle

1. The life cycle of StatelessWidget

Since the StatelessWidget has no state, its life cycle is simple: call the constructor, then call build(), and no more:

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    returnMaterialApp( home: HomePage(), ); }}class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("title")),
      body: HomeContent("hello world")); }}// The lifecycle of the StatelessWidget
class HomeContent extends StatelessWidget {
  final String message;

  HomeContent(this.message) {
    print("Constructor called");
  }

  @override
  Widget build(BuildContext context) {
    print("Call build method");
    returnText(message); }}Copy the code

Log output:

I/flutter (3092): constructor called I/flutter (3092): call build methodCopy the code

2. Lifecycle of StatefulWidget

methods instructions
createState Framework will by calling StatefulWidget. CreateState to create a State.
initState The newly created State will be associated with a BuildContext where State is considered installed and initState will be called. In general, we can rewrite this function to initialize it.
didChangeDependencies This function is called after the initState call. In fact, this function is always called by the Framework when the dependency of the State object changes.
build After the above steps, the system decides that a State is ready and calls Build to build the view. We need to return a Widget in this function.
deactivate Deactivate This function is called when State is temporarily removed from the view tree. It is also called when the page switches, because State’s position in the view tree changes and needs to be temporarily removed before being added.
dispose The Framework calls this function when State is permanently removed from the view tree. Triggered before destruction, we can do the final resource release here. The deactivate function is always called before calling this function.
didUpdateWidget This function is called when the configuration of the Widget changes. For example, this function is called when hot overloading occurs. After calling this function, the build function is called.
setState When you need to update the view of State, you need to call this function manually, which triggers the build function.
  • Methods that extract to: www.cxybcw.com/45008.html
  • The official documentation (full) : API. Flutter. Dev/flutter/wid…
// StatefulWidget's life cycle
class HomeContent extends StatefulWidget {
  HomeContent(String message) {
    print(1. Call the constructor method of HomeContent);
  }

  @override
  _HomeContentState createState() {
    print("2. Call the createState method of HomeContent");
    return_HomeContentState(); }}class _HomeContentState extends State<HomeContent> {
  _HomeContentState() {
    print(3. Call the constructor method of _HomeContentState);
  }

  @override
  void initState() {
    // Note: super(@mustcallsuper) must be called
    super.initState();
    print("4. Call the initState method of _HomeContentState");
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("Call the didChangeDependencies method of _HomeContentState");
  }

  @override
  void didUpdateWidget(covariant HomeContent oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("Call the didUpdateWidget method of _HomeContentState");
  }

  @override
  Widget build(BuildContext context) {
    print("5. Call the build method of _HomeContentState");
    return Container();
  }

  @override
  void dispose() {
    super.dispose();
    print("6. Call the dispose method of _HomeContentState"); }}Copy the code

Log result:

// Interface initializes I/flutter (3092): 1. Call the HomeContent constructor method I/flutter (3092): 2. Call HomeContent createState method I/flutter (3092): 3. Call the constructor method I/flutter (3092): 4. Call the initState method I/flutter (3092) of _HomeContentState: Call the didChangeDependencies method I/ FLUTTER (3092) of _HomeContentState: 5. Call the build method of _HomeContentState // click the count button I/ FLUTTER (3092): 5. Call the build method of _HomeContentStateCopy the code

Logs in Dispose () are not printed because the Widget is not removed in the Demo here