Flutterapp
Flutter code structure
Basic framework
Import packages.
import 'package:flutter/material.dart';
This line of code acts as an import of the Material UI component library. Material is a standard visual design language for mobile and web, and Flutter provides a rich set of Material style UI components by default. 2.
application portal.
void main() => runApp(MyApp());
- Similar to C/C++, Java,
main
function in Flutter application is the entry point of the application. Themain
function calls therunApp
method, whose function is to start the Flutter application.runApp
takes aWidget
parameter, which in this case is aMyApp
object, andMyApp()
is the root component of the Flutter application. - The
main
function uses the (=>
) notation, which is shorthand for a one-line function or method in Dart.
- Similar to C/C++, Java,
Application structure.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
//application name
title: 'Flutter Demo',
theme: new ThemeData(
//blue theme
primarySwatch: Colors.blue,
),
//application home page route
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}The
MyApp
class represents a Flutter application that inherits from theStatelessWidget
class, which means that the application itself is also a widget.In Flutter, most things are widgets (later "components" or "widgets"), including alignment, padding, layout, etc., which are all are provided in the form of widgets.
Flutter calls the
build
method of a component when building a page. The main job of a widget is to provide a build() method to describe how to build the UI interface (usually by combining and assembling other base widgets).MaterialApp
is the Flutter APP framework provided in the Material library, through which you can set the name, theme, language, home page and routing list of the application.MaterialApp
is also a widget.home
is the home page of the Flutter app, it is also a widget.
Home page component
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
}
MyHomePage
is the home page of the Flutter application, it inherits from the StatefulWidget
class, which means it is a stateful widget (a stateful component). For now, let's just briefly consider that a stateful widget is different from a stateless widget in two ways.
Stateful widgets can have states that are mutable during the widget lifecycle, while Stateless widgets are immutable.
Stateful widget consists of at least two classes.
- A
StatefulWidget
class. - A
State
class; theStatefulWidget
class itself is immutable, but the state held in theState
class may change during the widget's lifecycle.
The
_MyHomePageState
class is the state class corresponding to theMyHomePage
class. Here, the reader may have noticed: Unlike theMyApp
class, there is nobuild
method in theMyHomePage
class, instead, thebuild
method has been moved to the_MyHomePageState
method.- A
State class
Next, let's see what is contained in _MyHomePageState
.
the state of the component. Since we only need to maintain a click counter, define a
_counter
state.``dart int _counter = 0; // used to record the total number of button clicks
`_counter` is the state that holds the number of button clicks with a "+" sign in the bottom right corner of the screen.Set the self-increment function for the status.
void _incrementCounter() {
setState(() {
_counter++;
});
}This function is called when the button is clicked. The function works by first self-incrementing
_counter
and then calling thesetState
method. The purpose of thesetState
method is to notify the Flutter framework that a state has changed. When the Flutter framework receives the notification, it will execute thebuild
method to rebuild the interface based on the new state. so you can rebuild anything that needs to be updated without having to modify individual widgets.Build UI interface
The logic for building the UI interface is in the
build
method. WhenMyHomePage
is created for the first time, the_MyHomePageState
class will be created, and when the initialization is complete, the Flutter framework will call thebuild
method of the widget to build the widget tree, and finally render the widget tree to the device screen . So, let's see what is done in thebuild
method of_MyHomePageState
.Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}Scaffold
is a page scaffold provided in the Material library that provides a default navigation bar, a header, and abody
property containing the main screen widget tree (later referred to as the "component tree" or "widget tree"). Component trees can be very complex. In the examples later in this book, routes are created viaScaffold
by default.- The component tree of
body
contains aCenter
component, andCenter
can align its child component trees to the center of the screen. In this case, theCenter
subcomponent is aColumn
component, and the role ofColumn
is to align all its subcomponents vertically along the screen; in this case, theColumn
subcomponent is twoText
s, and the firstText
displays the fixed text "You have pushed the button this many times:", and the secondText
displays the value of the_counter
state. - The
floatingActionButton
is the hover button with+
in the bottom right corner of the page, itsonPressed
property accepts a callback function that represents its handler when it is clicked, in this case the_incrementCounter
method is directly used as its handler function.
Now, let's string together the entire counter execution flow: when the floatingActionButton
button in the bottom-right corner is clicked, the _incrementCounter
method is called. In the _incrementCounter
method, first the _counter
counter (state) will be self-incremented, then setState
will notify the Flutter framework that the state has changed, then the Flutter framework will call the build
method to rebuild the UI with the new state and finally display it on the device screen.
Why put the build method in State and not in StatefulWidget?
Now, let's answer the question raised earlier, why is the build()
method placed in State (instead of StatefulWidget
) ? This is mainly to increase the flexibility of development. If the build()
method is placed in the StatefulWidget
there are two problems.
Inconvenient state access
Imagine if our
StatefulWidget
has many states, and each time the state changes, we have to call thebuild
method, since the state is stored in State, if thebuild
method is inStatefulWidget
, then thebuild
method and the state are in two separate classes, so it will be very inconvenient to read the state when building! would be very inconvenient! Imagine if you actually put thebuild
method in a StatefulWidget, since the process of building the UI depends on the State, thebuild
method would have to have aState
parameter, something like the following.Widget build(BuildContext context, State state){
//state.counter
...
}In this case, you can only declare all the state of the State as public, so that you can access the state outside the State class! However, by making the state public, the state will no longer be private, which means that modifications to the state will become uncontrollable. But if you put the
build()
method in the State, the build process not only has direct access to the state, but also does not need to expose the private state, which is very convenient.Inheriting
StatefulWidget
is inconvenientFor example, Flutter has a base class
AnimatedWidget
for animated widgets, which inherits from theStatefulWidget
class. An abstract methodbuild(BuildContext context)
is introduced inAnimatedWidget
, and all animated widgets that inherit fromAnimatedWidget
have to implement thisbuild
method. Now imagine that if theStatefulWidget
class already has abuild
method, as described above, thebuild
method needs to receive a state object, which means that theAnimatedWidget
has to pass its own State object (noted as _ animatedWidgetState) to its child class, because the child class needs to call the parent class'sbuild
method in itsbuild
method, and the code might look like this.class MyAnimationWidget extends AnimatedWidget{
@override
Widget build(BuildContext context, State state){
//since the subclass is going to use the AnimatedWidget's state object _animatedWidgetState.
//so the AnimatedWidget must somehow expose its state object _animatedWidgetState
// Expose it to its subclasses
super.build(context, _animatedWidgetState)
}
}This obviously doesn't make sense, because
- the state object of
AnimatedWidget
is an internal implementation detail ofAnimatedWidget
and should not be exposed to the outside. - if the parent class state is to be exposed to the child class, then there must be a passing mechanism, and it is pointless to do this set of passing mechanism, because the passing of state between parent and child classes is irrelevant to the logic of the child class itself.
- the state object of
To sum up, it can be found that for StatefulWidget
, putting the build
method in State can bring a lot of flexibility to the development.