Project directory

Flutter_app ├ ─ ─ android # android directory ├ ─ ─ the build # build directory ├ ─ ─ ios # ios directory ├ ─ ─ lib # development directory (the equivalent of the SRC directory) | ├ ─ ─. Main dart # entry documents (equivalent to Index.js) ├─ Test # ├─.gitignore # Git Set to ignore the file content ├ ─ ─ pubspec. Lock # project depend on the lock information (equivalent to a package of NPM - lock. Json) └ ─ ─ pubspec. Yaml # project depend on the configuration (equivalent to a package of NPM. Json)Copy the code

Entrance to the file

Dart the entry file for the Flutter project is lib/main.dart, which has an entry method.

Entry method

// The entry method
void main() { 
	// Details
}
Copy the code

Root function

void main() {
	runApp(
		// Details
	);
}
Copy the code

The runApp function takes a component and makes it the root of the component tree, and the framework forces the root component to cover the entire screen.

UI library Material

import 'package:flutter/material.dart';
Copy the code

Mater is a standard MOBILE and Web UI framework. It is a set of Google design specifications. The Flutter project is based on Material.

  • Website: www.material.io
  • Chinese language: Material – IO

Widget (component)

Everything in a Flutter is a component, and a Flutter as a component generally falls into one of two categories.

  • StatelessWidget

    Stateless components, widgets whose state cannot be changed

  • StatefulWidget

    Stateful components, the states held by them, can change during the Widget life cycle; if we want to change the data in the page, we need to use the StatefulWidget.

Custom Components

To make the code more readable, you can isolate parts of the code into separate widgets. Our custom Widget needs to inherit the components provided by Flutter. The component that we inherit has a build method. We need to put our code into the build method.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text(
          'Hello Flutter', textDirection: TextDirection.ltr, ), ), ); }}Copy the code

MaterialApp

field type
navigatorKey GlobalKey
Home (start page) Widget
Routes (Routing list) Map<String, WidgetBuilder>
InitialRoute (initialRoute name) String
OnGenerateRoute (Generate route) RouteFactory
onUnknownRoute RouteFactory
navigatorObservers List
Builder TransitionBuilder
Title (App title) String
OnGenerateTitle (Generate app title) GenerateAppTitle
Color (color) Color
Theme (Theme configuration) ThemeData
Locale Locale
Delegates to localized delegation-agent 可迭代
localeResolutionCallback LocaleResolutionCallback
SupportedLocales (Application Support area) 可迭代
DebugShowMaterialGrid (whether to display Material grid) bool
ShowPerformanceOverlay (Display performance monitoring overlay) bool
CheckerboardRasterCacheImages cache (checkerboard grating image) bool
CheckerboardOffscreenLayers (checkerboard layer) bool
ShowSemanticsDebugger (shows semantic debugger) bool
Whether debugShowCheckedModeBanner (showing the DEBUG banner) bool

Scaffold

The Scaffold is the scaffolding for the Flutter application and is used to provide the basic layout of the Flutter project.

  • appBar

    An Appbar (Android ActionBar, Toolbar) that appears at the top of the screen

  • body

    The main Widget for the current interface

  • floatingActionButton

    FAB defined in paper and ink design, the main functional buttons of the interface

  • .

App structure

Common text components

  • Container
    • Child (Declare child component)
    • padding/margin
      • EdgeInsets.all()
      • EdgeInsets.fromLTRB()
      • EdgeInsets.only()
    • decoration
      • BoxDecoration(border, Rounded corner, gradient, Shadow, background color, background image)
    • alignment
      • Alignment content Alignment
    • transform
      • Matrix4 (Pan, rotate, scale, bevel)
  • Column
    • The main axis in Column is vertical
    • MainAxisAlignment: Spindle alignment
    • CrossAxisAlignment: crossAxisAlignment
  • Row
    • The main axis of Row is horizontal, and other attributes are the same as Column
  • Text (the component used to display Text, which is the most common component)
    • TextDirection
    • TextStyle
      • Colors (text Colors)
      • FontWeight
      • FontStyles
    • TextAlign
    • Text flow (TextOverflow)
    • MaxLines (specifies the number of lines to display)
  • RichText
    • If a paragraph of text needs to display different styles,TextThe component does not meet our requirements and needs to be used at this timeRichText.
  • TextSpan
    • Similar to the SPAN tag in HTML, TextSpan and RichText can be used together to achieve different style layouts.

Third-party Components

dio

  • Dio is a powerful Dart Http request library (similar to AxiOS)

    Pub. Dev/packages/di…

  • Using the step

    • Add dio dependencies in pubsepc.yaml
    • Install dependencies (pub get | flutter packages get | vs save configuration in code, download)
    • The introduction ofThe import 'package: do/dio. Dart ";
    • Use: pub. Dev/documentati…

Flutter_swiper

  • The best wheel casting component in Flutter for Android and iOS
    • Pub. Dev/packages/fl…
  • Using the step
    • Add the Flutter_swiper dependency in pubsepc.yaml
    • Install dependencies (pub get | flutter packages get | vs save configuration in code, download)
    • The introduction ofThe import 'package: flutter_swiper/flutter_swiper dart ";
    • use

The life cycle

  • When the initState() component object is inserted into the element tree
  • DidChangeDependencies () when the dependencies of the current state object change
  • Build () component renders
  • SetState () when the internal state of the component object changes
  • DidUpdateWidget () component configuration updates
  • Deactivate () when the component object is temporarily removed from the element tree
  • Dispose () component object is permanently removed from the element tree

Routing and Navigation

Introduction of routing

  • Route

    A route is an abstraction of a screen or page

  • Navigator

    • A component that manages routes, and the Navigator can jump between pages by routing onto and off the stack
    • Commonly used attributes
      • InitalRoute: initializes the route, which is the default page
      • OnGenerateRoter: Matches dynamic routes based on rules
      • OnUnknownRoute: indicates the unknown route, which is 404
      • Routes: indicates a route set

Anonymous routing

  • Navigator

    • Push (jump to specified component)

      Navigator.push(
      	context,
      	MaterialPageRoute(
      		builder: (context) => Demo(),
      	),
      );
      Copy the code
    • Pop (Rollback)

      Navigator.pop(context);
      Copy the code

After routing

  • The statement routing

    • Routes Routing table (Map type)
    • InitalRoute (initial route)
    • onUnknownRoute
  • Example Jump to the named route

    Navigator.pushNamed(context,'Route Name');
    Copy the code
  • Configuration is as follows

    return MaterialApp(
    	title: 'Flutter Demo',
    	routes: {
        'home':(context)=>Home(),
    		'demo': (context) => Demo(),
    	},
    	// initialRoute: 'home',
    	onUnknownRoute: (RouteSettings setting) => MaterialPageRoute(
    		builder: (context) => UnknownPage(),
    	),
    	home: MyHomePage(title: 'Flutter Demo Home Page'));Copy the code

Dynamic routing

  • Dynamic routing refers to the route specified by the onGenerateRoute attribute. The principle of dynamic routing is to match the transmitted route.

    MaterialApp(
    	title: 'Flutter Demo',
    	onGenerateRoute: (RouteSettings setting) {
        print('Current path :' + setting.name);
        
        if (setting.name == '/') {
          return MaterialPageRoute(builder: (context) => Home());
        }
        
        if (setting.name == 'demo') {
          return MaterialPageRoute(builder: (context) => Demo());
        }
    
        var uri = Uri.parse(setting.name);
        print(uri.pathSegments);
    
        if (uri.pathSegments.length == 2 && uri.pathSegments.first == 'demo') {
          var id = uri.pathSegments[1];
          return MaterialPageRoute(builder: (context) => Demo(id: id));
        }
        returnMaterialPageRoute(builder: (context) => UnknownPage()); });Copy the code

Screen adaptation

  • Screen adaptation

    • Screen sizes vary, so it’s important to ensure that an application behaves consistently across different terminals
  • flutter_screenutil

    • Pub. Dev/packages/fl…
  • Principle of adaptation

    • Design size (for example: iphone6 is 750*1334)
    • Terminal size (obtained from window or mediaQuery.of (context))
    • Enlarge or reduce the size of the design draft on the terminal
  • Design size

    • DesignWidth: 750 px
    • DesignHeight: 1334 px
  • Terminal size (dynamic acquisition)

    • DeviceWidth: 1080 px
    • DeviceHeight: 1920 px
  • scaling

    • scaleWidth = deviceWidth / designWidth
    • scaleHeight = deviceHeight / designHeight
  • The installation

    Pub. Dev/packages/fl…

  • Initialize the design dimensions

    ScreenUtilInit(designSize: Size(375.667),...). ;Copy the code
  • Set fit size

    • Flutter before 1.2
      • width: ScreenUtil().setWidth(100);
      • Height:ScreenUtil().setHeight(100);
    • Flutter after 1.2
      • width: 100.w
      • Height: 100.h

Mixed development

Embed native View

  1. Create an iOS View in the Runner directory that inherits the FlutterPlatformView and returns a simple UILabel:

    //
    // MyFlutterView.swift
    // Runner
    //
    // Created by Wukong on 2021/5/31
    //
    
    import Foundation
    import Flutter
    
    class MyFlutterView: NSObject.FlutterPlatformView {
        
        let label = UILabel(a)init(_ frame: CGRect.viewID: Int64.args :Any?.messenger :FlutterBinaryMessenger) {
            super.init(a)if(args is NSDictionary) {let dict = args as! NSDictionary
                label.text  = dict.value(forKey: "text") as! String}}func view(a) -> UIView {
            return label
        }
        
    }
    Copy the code
  2. Create MyFlutterViewFactory class

    //
    // MyFlutterViewFactory.swift
    // Runner
    //
    // Created by Wukong on 2021/5/31
    //
    
    import Foundation
    import Flutter
    
    class MyFlutterViewFactory: NSObject.FlutterPlatformViewFactory {
        
        var messenger:FlutterBinaryMessenger
        
        init(messenger:FlutterBinaryMessenger) {
            self.messenger = messenger
            super.init()}func create(withFrame frame: CGRect.viewIdentifier viewId: Int64.arguments args: Any?) -> FlutterPlatformView {
            return MyFlutterView(frame,viewID: viewId,args: args,messenger: messenger)
        }
        
        func createArgsCodec(a) -> FlutterMessageCodec & NSObjectProtocol {
            return FlutterStandardMessageCodec.sharedInstance()
        }
    }
    Copy the code
  3. Register in the AppDelegate

    import UIKit
    import Flutter
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication.didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        
        let registrar:FlutterPluginRegistrar = self.registrar(forPlugin: "plugins.flutter.io/custom_platform_view_plugin")!
        let factory = MyFlutterViewFactory(messenger: registrar.messenger())
        registrar.register(factory, withId: "plugins.flutter.io/custom_platform_view")
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    Copy the code
  4. Create a PlatformViewDemo class in the Flutter/lib directory

    import 'package:flutter/foundation.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    class PlatformViewDemo extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        Widget platformView() {
          if (defaultTargetPlatform == TargetPlatform.iOS) {
            return UiKitView(
              viewType: 'plugins.flutter.io/custom_platform_view',
              creationParams: {'text': 'I'm an IOS native View'},
              creationParamsCodec: StandardMessageCodec(),
            );
          }
          return null;
        }
    
        returnScaffold( appBar: AppBar(), body: Center( child: platformView(), ), ); }}Copy the code

Communicate with native

There are three ways for Flutter to communicate with Native terminal:

  • MethodChannel: The Flutter and the Native can call each other, and the result can be returned after the call. The Native can call the Flutter actively, and the Flutter can call the result actively, which is two-way communication. This is the most common method, and Native calls need to be executed in the main thread.
  • BasicMessageChannel: Used to encode and decode messages using a specified codec. It is bidirectional communication and can be actively invoked by either the Native end or the Flutter.
  • EventChannel: Used for the communication of Event Streams. The Native end actively sends data to Flutter, which is usually used to monitor the state of Flutter, such as network changes and sensor data.

MethodChannel

The Flutter end creates a MethodChannel to communicate with the native end:

/ / com. Flutter. Guide. MethodChannel is MethodChannel, the name of the primary side and the matching.
var channel = MethodChannel('com.flutter.guide.MethodChannel');
Copy the code

Send a message:

var result = await channel.invokeMethod('sendData', {'name': 'xiazanzhang'.'age': 18})
Copy the code
  • The first parameter represents method, the name of the method, which is parsed by the native end.
  • The second parameter represents a parameter of any type. Map is usually used for multiple parameters.
  • Return the Future, the data returned by the native end.

Use as follows:

  1. Create the MethodChannelDemo class in the Runner directory as follows

    //
    // MethodChannelDemo.swift
    // Runner
    //
    // Created by Wukong on 2021/5/31
    //
    
    import Flutter
    import UIKit
    
    public class MethodChannelDemo {
        var count =  0
        var channel:FlutterMethodChannel
        init(messenger: FlutterBinaryMessenger) {
            channel = FlutterMethodChannel(name: "com.flutter.guide.MethodChannel", binaryMessenger: messenger)
            channel.setMethodCallHandler { (call:FlutterMethodCall, result:@escaping FlutterResult) in
                if (call.method = = "sendData") {
                    if let dict = call.arguments as? Dictionary<String.Any> {
                        let name:String = dict["name"] as? String ?? ""
                        let age:Int = dict["age"] as? Int ?? -1
                        result(["name":"hello,\(name)"."age":age])
                    }
                }
            }
            startTimer()
        }
        
        func startTimer(a) {
            var timer = Timer.scheduledTimer(timeInterval:1, target: self, selector:#selector(self.tickDown),userInfo:nil,repeats: true)}@objc func tickDown(a){
            count + = 1
            var args = ["count":count]
            channel.invokeMethod("timer", arguments:args)
        }
    }
    Copy the code
  2. Modify the App Delegate class

    import UIKit
    import Flutter
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication.didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        
        // Embed the native view
        let registrar:FlutterPluginRegistrar = self.registrar(forPlugin: "plugins.flutter.io/custom_platform_view_plugin")!
        
        // The Flutter sends messages to the iOS View
        let factory = MyFlutterViewFactory(messenger: registrar.messenger())
        registrar.register(factory, withId: "plugins.flutter.io/custom_platform_view")
        
        // MethodChannel: communicates with native
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        MethodChannelDemo(messenger: controller.binaryMessenger)
        
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    Copy the code
  3. Create a new MethodChannelDemo class in the Flutter project

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    class MethodChannelDemo extends StatefulWidget {
      @override
      _MethodChannelDemoState createState() => _MethodChannelDemoState();
    }
    
    class _MethodChannelDemoState extends State<MethodChannelDemo> {
      var channel = MethodChannel('com.flutter.guide.MethodChannel');
      var _data;
      var _count;
    
      @override
      void initState() {
        super.initState();
        channel.setMethodCallHandler((call) {
          setState(() {
            _count = call.arguments['count'];
          });
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Column(
            children: [
              SizedBox(
                height: 50,
              ),
              ElevatedButton(
                child: Text('Send data to native'),
                onPressed: () async {
                  var result = await channel
                      .invokeMethod('sendData', {'name': 'xiazanzhang'.'age': 18});
                  var name = result['name'];
                  var age = result['age'];
                  setState(() {
                    _data = '$name.$age';
                  });
                },
              ),
              Text('Native return data:$_data'),
              Text('Receive native active send data:$_count'),,),); }}Copy the code

BasicMessageChannel

The Flutter end creates a MethodChannel to communicate with the native end:

/ / com. Flutter. Guide. BasicMessageChannel is BasicMessageChannel, the name of the primary side and the matching.
var channel = BasicMessageChannel('com.flutter.guide.BasicMessageChannel',StandardMessageCodec());
Copy the code

Send a message:

var result = await channel.send({'name': 'xiazanzhang'.'age': 18});
Copy the code
  • The parameter type is arbitrary. Map is usually used for multiple parameters.
  • Return the Future, the data returned by the native end.

Use as follows:

  1. Create the MethodChannelDemo class in the Runner directory as follows

    //
    // BasicMessageChannelDemo.swift
    // Runner
    //
    // Created by Wukong on 2021/5/31
    //
    
    import Flutter
    import UIKit
    
    public class BasicMessageChannelDemo {
        
        var channel:FlutterBasicMessageChannel
        
        init(messenger: FlutterBinaryMessenger) {
            channel = FlutterBasicMessageChannel(name: "com.flutter.guide.BasicMessageChannel", binaryMessenger: messenger)
            channel.setMessageHandler { (message, reply) in
                if let dict = message as? Dictionary<String.Any> {
                    let name:String = dict["name"] as? String ?? ""
                    let age:Int = dict["age"] as? Int ?? -1
                    reply(["name":"hello,\(name)"."age":age])
                }
            }
        }
    }
    Copy the code
  2. Modify the AppDelegate class by adding the following code to the Application method

      BasicMessageChannel: communicates with the Flutter
      BasicMessageChannelDemo(messenger: controller.binaryMessenger)
    Copy the code
  3. Create a new BasicMessageChannelDemo class in the Flutter project

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    class BasicMessageChannelDemo extends StatefulWidget {
      @override
      _BasicMessageChannelDemoState createState() =>
          _BasicMessageChannelDemoState();
    }
    
    class _BasicMessageChannelDemoState extends State<BasicMessageChannelDemo> {
      var channel = BasicMessageChannel(
          'com.flutter.guide.BasicMessageChannel', StandardMessageCodec());
    
      var _data;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Column(
            children: [
              SizedBox(
                height: 50,
              ),
              ElevatedButton(
                child: Text('Send data to native'),
                onPressed: () async {
                  var data = {'name': 'xiazanzhang'.'age': 18};
                  var result = await channel.send(data) as Map;
                  var name = result['name'];
                  var age = result['age'];
                  setState(() {
                    _data = '$name.$age';
                  });
                },
              ),
              Text('Native return data:$_data'),,),); }}Copy the code

EventChannel

The Flutter end creates an EventChannel to communicate with the native end:

. / / com. Flutter. Guide the EventChannel is the title of the EventChannel primary side and the matching.
var _eventChannel = EventChannel('com.flutter.guide.EventChannel');
Copy the code

Listen for messages sent from the native end:

var _data;
  @override
  void initState() {
    super.initState();
    _eventChannel.receiveBroadcastStream().listen(_onData);
  }

  _onData(event){
    setState(() {
      _data = event;
    });
  }
Copy the code

Use as follows:

  1. Create the MethodChannelDemo class in the Runner directory as follows

    //
    // EventChannelDemo.swift
    // Runner
    //
    // Created by Wukong on 2021/5/31
    //
    
    import Flutter
    import UIKit
    
    public class EventChannelDemo:NSObject.FlutterStreamHandler{
        
        var channel:FlutterEventChannel?
        var count =  0
        var events:FlutterEventSink?
        
        public override init() {
            super.init()
        }
        
        convenience init(messenger: FlutterBinaryMessenger) {
            
            self.init()
            
            channel = FlutterEventChannel(name: "com.flutter.guide.EventChannel", binaryMessenger: messenger) channel? .setStreamHandler(self) startTimer() } func startTimer() { let timer = Timer.scheduledTimer(timeInterval:1, target: self, selector:#selector(self.tickDown),userInfo:nil,repeats: true)}@objc func tickDown(){
            count += 1
            let args = ["count":count]
            if(events ! = nil){ events! (args) } } public func onListen(withArguments arguments: Any? , eventSink events:@escaping FlutterEventSink) -> FlutterError? {
            self.events = events
            return nil;
        }
        
        public func onCancel(withArguments arguments: Any?) -> FlutterError? {
            self.events = nil
            returnnil; }}Copy the code
  2. Modify the AppDelegate class by adding the following code to the Application method

    // EventChannel: communicates with Flutter
    EventChannelDemo(messenger: controller.binaryMessenger)
    Copy the code
  3. Create a new BasicMessageChannelDemo class in the Flutter project

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    class EventChannelDemo extends StatefulWidget {
      @override
      _EventChannelDemoState createState() => _EventChannelDemoState();
    }
    
    class _EventChannelDemoState extends State<EventChannelDemo> {
      var _eventChannel = EventChannel('com.flutter.guide.EventChannel');
      var _data;
      @override
      void initState() {
        super.initState();
        _eventChannel.receiveBroadcastStream().listen(_onData);
      }
    
      _onData(event) {
        setState(() {
          _data = event;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Center(
            child: Text('Listen for native returned data:$_data'),),); }}Copy the code