Flutter installation

Download and install Flutter Mac/Flutter Windows

Flutter Development wechat Project (I)

1. Develop a HomePage page

  1. Operation effect:

  1. Function is introduced

  2. The code on

  • KYLRootPage is the root page
class KYLRootPage extends StatefulWidget { @override State<StatefulWidget> createState() { // TODO: implement createState return _RootPageState(); } } class _RootPageState extends State<KYLRootPage> { int _currentIndex = 0; List<Widget> pages = [Scaffold(appBar: appBar (title: Text(' wechat '),), body: Center(child: Text(' wechat homepage '),), Scaffold(appBar: appBar (title: Text(' address book '),), body: Center(child: Text(' address book list '),), Scaffold(appBar: appBar (title: Text(' discover '),), body: Center(child: The Text (' found list),),), Scaffold (appBar: appBar (title: Text (' I '),), body: Center (child: Text (' my page '),),)]; @override Widget build(BuildContext context) { // TODO: implement build return Container( child: Scaffold( bottomNavigationBar: BottomNavigationBar( onTap: (int index) { _currentIndex = index; }, type: BottomNavigationBarType.fixed, fixedColor: Colors.green, currentIndex: _currentIndex, items: <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.chat), title: BottomNavigationBarItem(icon: icon (Icons. Bookmark), title: Text(' address book '),, BottomNavigationBarItem(icon: icon (Icons. History), title: Text(' find '),), BottomNavigationBarItem(icon: icon (Icons. Person_outline), title: Text(' I '),), body: pages[_currentIndex], ), ); }}Copy the code
  • main.dart
import 'package:flutter/material.dart'; import 'KYLRootPage.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( // This is the theme of your application. // // Try running your application with "flutter run". You'll see the // application has a blue toolbar. Then, without quitting the app, try // changing the primarySwatch below to Colors.green and then invoke // "hot reload" (press "r" in the console where you ran "flutter run", // or simply save your changes to "hot reload" in a Flutter IDE). // Notice that the counter didn't reset back to zero; the application // is not restarted. primarySwatch: Colors.blue, ), home: KYLRootPage(), ); }}Copy the code

2. Explain the knowledge points used

2.1 BottomNavigationBar

This is a custom Button that you can place on top of the BottomNavigationBar, which implements Material(Android) and Cupertino(iOS) styles.

Scaffold is the scaffolding for the Root Widget-MaterialApp. It encapsulates AppBar, Drawer, SnackBar, BottomNavigationBar and so on that Material Design App will use. The BottomNavigationBarType has fixed and shifting styles, which can be distinguished only if there are more than three. Generally, we use fixed type to experience consistency.

The BottomNavigationBar is a StatefulWidget that can analyze such a component by following these steps:

  1. Let’s look at the state it’s holding;
  2. Look at his life cycle implementation;
  3. Take a closer look at its build method.
  • Holding state
List<AnimationController> _controllers = <AnimationController>[];
List<CurvedAnimation> _animations;

// A queue of color splashes currently being animated.
final Queue<_Circle> _circles = Queue<_Circle>();

// Last splash circle's color, and the final color of the control after
// animation is complete.
Color _backgroundColor;
Copy the code

The first three properties are all related to animation, and the fourth is setting the background. Why does the BottomNavigationBar have no variable to mark which item is currently selected?

One of the rules of functional programming is to keep functions as pure as possible. CurrentIndex is a property that relies on being passed in from the outside and refires Render every time it changes. If you maintain it yourself, you also need to provide a callback method for external calls that returns the latest currentIndex value.

  • Lifecycle approach
@override //initState has an operation that is implicit: _controllers[widget.currentIndex]. Value = 1.0; void initState() { super.initState(); _resetState(); } // Recycle the resource Override void dispose() {for (AnimationController controller in _controllers) controller.dispose(); for (_Circle circle in _circles) circle.dispose(); super.dispose(); } // The Flutter system calls back to this method when properties change. Reinitialize directly when the number of items changes; When index changes, animate accordingly. @override void didUpdateWidget(BottomNavigationBar oldWidget) { super.didUpdateWidget(oldWidget); // No animated segue if the length of the items list changes. if (widget.items.length ! = oldWidget.items.length) { _resetState(); return; } if (widget.currentIndex ! = oldWidget.currentIndex) { switch (widget.type) { case BottomNavigationBarType.fixed: break; case BottomNavigationBarType.shifting: _pushCircle(widget.currentIndex); break; } _controllers[oldWidget.currentIndex].reverse(); _controllers[widget.currentIndex].forward(); } if (_backgroundColor ! = widget.items[widget.currentIndex].backgroundColor) _backgroundColor = widget.items[widget.currentIndex].backgroundColor; Override Widget build(BuildContext context) {}Copy the code
  • Analysis build method
@ override Widget build (BuildContext context) {/ / check the debug assert (debugCheckHasDirectionality (context)); assert(debugCheckHasMaterialLocalizations(context)); // Labels apply up to _bottomMargin padding. Remainder is media padding. final double additionalBottomPadding = Math. Max (MediaQuery. Of (context). The padding. The bottom - _kBottomMargin, 0.0); // set the backgroundColor according to BottomNavigationBarType. switch (widget.type) { case BottomNavigationBarType.fixed: break; case BottomNavigationBarType.shifting: backgroundColor = _backgroundColor; break; } return Semantics(// Use the Semantics function to implement the object object. Container: true, explicitChildNodes: true, child: Stack(children: <Widget>[c-jam. Fill (child: Material(// Casts shadow. Elevation: 8.0, color: backgroundColor, ), ), ConstrainedBox( constraints: BoxConstraints(minHeight: kBottomNavigationBarHeight + additionalBottomPadding), child: Stack( children: <Widget>[toy. Fill (// click on the corner of a circle of circles animation child: CustomPaint(Painter: _RadialPainter(circles: _circles.toList(), textDirection: Directionality.of(context), ), ), ), Material( // Splashes. type: MaterialType.transparency, child: Padding( padding: EdgeInsets.only(bottom: additionalBottomPadding), child: MediaQuery.removePadding( context: context, removeBottom: BottomNavigationBarItem Child: _createContainer(_createTiles()),))])])))))); }}Copy the code
  • _BottomNavigationTile see
Widget _buildIcon() { ... // Build Icon} Widget _buildFixedLabel() {.... // Use the matrix to animate the text, // The font size should grow here when active, but because of The way it doesn't grow smoothly if we just animate // the font size, so we use a transform instead. child: Transform( transform: Matrix4.diagonal3( Vector3.all( Tween<double>( begin: _kInactiveFontSize / _kActiveFontSize, end: BottomCenter, child: item.title,),),); } Widget _buildShiftingLabel() { return Align( ..... // The label is fade, and only the currently selected label child: FadeTransition will be displayed (alwaysIncludeSemantics: true, opacity: animation, child: DefaultTextStyle.merge( style: const TextStyle( fontSize: _kActiveFontSize, color: Colors.white, ), child: item.title, ), ), ), ); } @override Widget build(BuildContext context) { int size; Widget label; / / generate different label switch (type) {case BottomNavigationBarType. Fixed: size = 1; label = _buildFixedLabel(); break; Case BottomNavigationBarType. Shifting: size = (flex * 1000.0). The round (); label = _buildShiftingLabel(); break; } return Expanded( .... children: <Widget>[ _buildIcon(), label, ], ), ), Semantics( label: indexLabel, }Copy the code

2.2 the Container

Introduction of 2.2.1.

Containers are all too common in Flutter. The official description is a widget that combines painting, positioning, and sizing widgets. It is a composite widget with drawing widgets, positioning widgets, and sizing widgets inside. Many of the widgets you’ll see later are made up of more basic widgets.

An 2.2.2.
  1. The components of a Container are as follows:

The innermost layer is the child element; The child element is first wrapped in the padding; Then add additional constraints to the constraints; Finally add margin.

  1. The process for drawing containers is as follows:

The transform effect is drawn first; Next, draw decoration; Then draw child; Finally, draw the ground decoration.

  1. The Container can be adjusted in two ways:

The Container tries to be large enough when it has no children. Unless constraints are unbounded, in which case the Container will try to be small enough. The Container of the string node resizesaccording to the size of its children, but the Container constructor resizesaccording to the parameters in the constructor if the Container constructor contains width, height, and constraints.

2.2.3. Attributes of Containers
  • Key: Unique identifier of Container, used to search for updates.

  • Alignment: Controls the alignment of the child. This attribute takes effect if the Container or its parent is larger than the child size. There are many alignment options.

  • Padding: The empty area inside the decoration. If there is a child, the child is inside the padding. The difference between padding and margin is that padding is contained within the content, while margin is the outer boundary. If you set the click event, the padding area will respond, but the margin area will not.

  • Color: Used to set the background color of the container. If the foregroundDecoration is set, the color effect may be obscured.

  • “Decoration” : the decoration behind the child. If “decoration” is set, the color attribute cannot be set. Otherwise, an error will be reported, and the color should be set in “decoration”.

  • ForegroundDecoration: Decoration painted in front of child.

  • Width: the width of the container, set to double. Infinity can be used to force the container to be full in width.

  • Height: The height of the container, set to double. Infinity forces the container to be full at the height.

  • Constraints: Additional constraints added to the child.

  • Margin: The blank area surrounding decoration and child, not part of the content area.

  • Transform: Sets the transformation matrix of container. The type is Matrix4.

  • Child: Content widget in container.

Example:

new Container( constraints: New BoxConstraints. Expand (height: the Theme of (context). TextTheme. Display1. FontSize * 1.1 + 200.0,), decoration: New BoxDecoration(border: new border. All (width: 2.0, color: color.red), color: color.grey, borderRadius: New Borderradius.all (new radius.circular (20.0)), image: new DecorationImage(image: new NetworkImage('http://h.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=0d023672312ac65c67506e77cec29e27/9f2f070828381f30de A167bbad014c086e06f06c. JPG '), centerSlice: new the Rect. FromLTRB (270.0, 180.0, 1360.0, 730.0),),), padding: Const EdgeInsets. All (8.0), alignment: align. center, child: new Text('Hello World', style: The Theme of (context). TextTheme. Display1. CopyWith (color: Colors. Black)), the transform: new Matrix4. RotationZ (0.3),)Copy the code
2.2.4. Use the Container

Container is one of the most frequently used widgets in the current project. In practice, I use Containers in the following situations, but not always, but also through other widgets.

  1. You need to set the interval (in this case, if it’s just a pure interval, you can also use Padding);
  2. Need to set the background color;
  3. When you need to set rounded corners or borders (ClipRRect can also be rounded);
  4. Need to Align (Align also works);
  5. When the background image needs to be set (Stack can also be used).
2.2.5. Source code analysis of Container
decoration = decoration ?? (color ! = null ? new BoxDecoration(color: color) : null),Copy the code

It can be seen that the setting of color is changed to decoration for drawing. If both decoration and color are included, an error will be reported.

@override Widget build(BuildContext context) { Widget current = child; if (child == null && (constraints == null || ! IsTight) {current = new LimitedBox(maxWidth: 0.0, maxHeight: 0.0, child: new ConstrainedBox(constraints: const BoxConstraints.expand()) ); } if (alignment ! = null) current = new Align(alignment: alignment, child: current); final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration; if (effectivePadding ! = null) current = new Padding(padding: effectivePadding, child: current); if (decoration ! = null) current = new DecoratedBox(decoration: decoration, child: current); if (foregroundDecoration ! = null) { current = new DecoratedBox( decoration: foregroundDecoration, position: DecorationPosition.foreground, child: current ); } if (constraints ! = null) current = new ConstrainedBox(constraints: constraints, child: current); if (margin ! = null) current = new Padding(padding: margin, child: current); if (transform ! = null) current = new Transform(transform: transform, child: current); return current; }Copy the code

The build function of a Container is not long, and drawing is a linear judgment process, covering widgets layer by layer to implement different styles. The innermost layer is child, and if empty or other constraints, the innermost layer contains a LimitedBox, Then Align, Padding, DecoratedBox, foreground DecoratedBox, ConstrainedBox, Padding, Transform. The source code for Container itself is not complicated, but rather its various layout representations. Keep in mind that if there are no internal constraints, then as large as the parent node can be, if there are internal constraints, then as large as the parent node can be.

2.3 Scaffold

The Scaffold implements the basic Material layout. Scaffold can be used to draw layout control elements that are displayed on a single interface defined in Material. Display drawers (e.g. left side bar), snack bars and bottom buttons (bottom sheets) are provided. Scaffold can be thought of as a container of layouts. This container is where we can draw our user interface.

  1. Source code analysis of Scaffold

  1. The main properties of Scaffold are described
  • AppBar: display a appBar related links at the top of their interface: flutterchina. The club/catalog/Sam…
  • Body: The main content displayed on the current interface
  • FloatingActionButton: A function button defined in Material.
  • PersistentFooterButtons: The buttons that are fixed to the bottom display. Material.google.com/components/…
  • Drawer: sidebar control
  • BottomNavigationBar: Displays the navigation bar button bar at the bottom.
  • BackgroundColor: backgroundColor
  • ResizeToAvoidBottomPadding: control interface content body whether or not to the bottom of the layout to avoid being covered, such as when the keyboard display, layout again to avoid being the keyboard cover. The default value is true.
  1. Code sample
class Scaffold extends StatefulWidget { /// Creates a visual scaffold for material design widgets. const Scaffold({ Key Key, enclosing appBar, / / lateral horizontal layout, usually displayed on the top (*) enclosing body, / / content (*) enclosing floatingActionButton, / / suspended button, This is pictured at the bottom right button (*). FloatingActionButtonLocation, / / / / suspend button position suspended button disappeared in [floatingActionButtonLocation] / animation this. FloatingActionButtonAnimator, / / presents a set of button in the bottom, Display on the [bottomNavigationBar], [body] under this. PersistentFooterButtons, / / a vertical panel, shown in the left, Initial in the hidden state (*) enclosing the drawer, enclosing endDrawer, / / in a series of horizontal button (*) at the bottom of the enclosing bottomNavigationBar, / / persistent prompt box at the bottom of the enclosing bottomSheet, This. BackgroundColor, // deprecated, Use [resizeToAvoidBottomInset] this. ResizeToAvoidBottomPadding, / / recalculate layout space enclosing resizeToAvoidBottomInset, / / whether the display to the bottom, The default is true status bar will be displayed to the top this. Primary = true, / / this. DrawerDragStartBehavior = DragStartBehavior. Down,}) : assert (primary! = null), assert(drawerDragStartBehavior ! = null), super(key: key);Copy the code
  1. Scaffold. Of usage instructions

About the Scaffold of function description: the docs. Flutter. IO/flutter/mat…

When snackbar or Bottom sheet is displayed, the ScaffoldState object needs to be retrieved by calling scaffold. of with the current BuildContext parameter. Then use the ScaffoldState. ShowSnackBar and ScaffoldState. ShowBottomSheet function to display.

Examples from the official source code above. I’ll use the SnackBar notation.

@override Widget build(BuildContext context) { return new RaisedButton( child: new Text('SHOW A SNACKBAR'), onPressed: () { Scaffold.of(context).showSnackBar(new SnackBar( content: new Text('Hello! '))); }); }Copy the code

When that Scaffold is actually created in the same builder, the builder’s BuildContext parameter cannot be used to find that Scaffold because it is “on top” of the returned widget. Return new Scaffold(app: XXXX) is used in the source code. In this case, we provide a new BuildContext with a Builder:

@override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('Demo') ), body: new Builder( // Create an inner BuildContext so that the onPressed methods // can refer to the Scaffold with Scaffold.of(). builder: (BuildContext context) { return new Center( child: new RaisedButton( child: new Text('SHOW A SNACKBAR'), onPressed: () { Scaffold.of(context).showSnackBar(new SnackBar( content: new Text('Hello! '))); },),); },),); }Copy the code

Officially, we can split our builder into multiple Widgets. New BuildContext is introduced to get Scaffold. Since the | the original address

Source code + information download