Flutter开发之基础知识

作为时下最留下的大前端跨平台开发框架,很多的公司和同学都开始了Flutter学习和应用,关于Flutter的基础知识,可以参考下面的两篇文章。
Flutter环境搭建
Flutter 基础知识点总结

接下来,我们将介绍一些Flutter应用开发中一些基本的知识。

Flutter基础知识

创建Flutter项目

在Flutter开发中,创建一个Flutter 项目通常有以下两种方式:

  • 使用flutter create命令,确保Flutter SDK配置了环境变量。
  • 使用安装了Flutter和Dart插件的IDE,如Android Studio和IntelliJ IDEA。

命令行方式创建Flutter的命令如下:

flutter create <projectname>

如果使用IDE创建Flutter项目,可以依次选择【File】->【New】->【New Flutter Project...】,如下图所示:
Flutter开发之基础知识

运行项目

在Flutter开发中,运行Flutter项目主要有两种方式,一种是命令方式,一种是IDE的方式。
命令方式运行Flutter如下所示:

flutter run -d 'iPhone X'
flutter run -d emulator-5554

其中,-d后面跟的是具体的设备名称,可以是Android或iOS模拟器的名字,也可以一台已经连接到电脑上的Android或iOS的设备。
相比命令方式,我们更推荐使用IDE图形化工具的方式,首先选择要运行的设备,然后选择main.dart入口文件,然后点击【运行】按钮即可运行Flutter项目,如下图:
Flutter开发之基础知识
除了上面的命令外,Flutter开发中常见的命令还有:

flutter emulator             //查看本地模拟器
flutter emulators --create --name xyz        //创建一个模拟器
flutter emulators --launch <emulator id>       //启动模拟器
flutter build apk;           //打包Android应用
flutter build apk –release;
flutter install;              //安装应用
flutter build ios;            //打包IOS应用
flutter build ios –release;
flutter clean;               //清理重新编译项目
flutter upgrade;            //升级Flutter SDK和依赖包
flutter channel;            //查看Flutter官方分支列表和当前项目使用的Flutter分支
flutter channel <分支名>;   //切换分支

除此之外,我们还可以点击 热重载按钮 (带有闪电⚡️图标的按钮)来开启热重载方法,如下图:
Flutter开发之基础知识

Flutter调试

Flutter提供了各种各样的工具和功能来帮助开发者调试Flutter应用程序,如果你使用的是VsCode作为开发工具,那么可以参考下面的调试技巧:

断点调试

在 Flutter 进行断点调试非常简单,只需要在 Vscode 上打上一个断点,按 F5 就会停在断点处。通过左边的调试栏,观察断点处的变量以及栈堆情况。
Flutter开发之基础知识

debugger调试

debugger代码调试只能运行在开发阶段,debugger调试是Flutter提供的debugger API ,和JavaScript的console类似。例如:

import 'dart:developer';

void someFunction(double offset) {
    debugger(when: offset > 30.0, message: 'offset 大于 30 时,中断');
    // ...
}

那么,当 offset 这个变量的值大于 30.0 时中断运行,并输出 message 的内容。

rendering 调试

rendering 调试即开启布局线调试,当打开 rendering 时会在界面上看到一些布局线,以便于修复布局效果。要开启rendering调试,需要在代码中添加debugPaintSizeEnabled。例如:

import 'package:flutter/rendering.dart';

void main() {
    debugPaintSizeEnabled = !true;
    runApp(new MyApp());
}

然后,重新运行项目即可看得效果。

日志调试

日志调试是软件开发中的一种很常见的调试方式,可以方便开发者查看程序运行的日志信息,现在流行的IDE几乎都集成了日志模块。 Android Studio和Vscode 里的控制台/调试控制台都可以看到。

当然,为了方便,我们也可以自己定义一个Debug类用于代码调试,例如:

class Debug {
    static log(String tag, String text) {
        print('[$tag] $text');
    }
    static info(String tag, String text) {
        print('[$tag] $text');
    }
    static success(String tag, String text) {
        print('[$tag] $text');
    }
    static error(String tag, String text) {
        print('[$tag] $text');
    }
}

真机调试

在Android 真机上运行Flutter程序,需要先开启开发者选项,开启的步骤如下:

  • 打开【开发者选项】和【 USB 调试】。
  • 使用 USB 将手机连接电脑,若手机出现提示,授权电脑访问手机。
  • 在命令执行 flutter devices 确认连接电脑的设备。
  • 然后使用 flutter run 命令运行 app。
  • 在手机上开启 USB 调试模式。

Flutter开发之基础知识

Hello Word

和很多的程序一样,Flutter程序也有一个启动页面,新建项目时系统默认的启动页面是main.dart,那么我们可以修改main.dart的代码。例如:

import 'package:flutter/material.dart';
 
void main() => runApp(new MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Welcome to Flutter',
      theme: new ThemeData(
        primaryColor: Colors.white,
      ),
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: new Text('Hello World'),
        ),
      ),
    );
  }
}

然后,运行上面的代码,可以看到如下的效果:
Flutter开发之基础知识

Flutter 项目结构

打开新建懂得Flutter工程,项目结构如下图所示:
Flutter开发之基础知识
可以发现,一个完整的Flutter项目目录结构如下:

┬
└ projectname
  ┬
  ├ android      - Android部分的工程文件
  ├ build        - 项目的构建输出目录
  ├ ios          - iOS部分的工程文件
  ├ lib          - 项目中的Dart源文件
    ┬
    └ src        - 包含其他源文件
    └ main.dart  - 自动生成的项目入口文件,类似RN的index.js文件
  ├ test         - 测试相关文件
  └ pubspec.yaml - 项目依赖配置文件类似于RN的 package.json

其中,对于开发者来说,比较重要的有以下几个文件:

  • android:android平台相关代码;
  • ios:ios平台相关代码;
  • lib:flutter相关代码,也是Flutter项目源码存放的地方;
  • test:存放测试代码;
  • pubspec.yaml:配置文件,一般存放一些第三方的依赖。

入口函数

我们知道,每个应用程序都有一个入口函数,Flutter项目的入口函数就是main.dart文件的main函数。

void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
       ...
    );
  }
}

在上面的代码中,返回了一个MaterialApp widget,MaterialApp可以理解为是UI的风格,MaterialApp是Android使用的风格,iOS则可以使用CupertinoApp风格。

Flutter主题

除了MaterialApp样式外,我们还可以使用全局主题或使用Theme来定义应用程序局部的颜色和字体样式。

全局主题

创建应用主题的方法是将ThemeData提供给MaterialApp构造函数,如果没有提供主题,Flutter将创建一个默认主题,全局主题的使用示例如下:

new MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        brightness: Brightness.light,
        primarySwatch: Colors.blue,
        primaryColor: Colors.cyan[600]
      ),
    );

局部主题

除了全局主题外,Flutter还支持创建特有的主题(局部主题)。具体使用时,数据实例化一个ThemeData并将其传递给Theme对象即可,如下所示:

new Theme(data: new ThemeData(accentColor: Colors.yellow), child: null),

当然,还可以扩展父主题,扩展父主题时无须覆盖所有的主题属性,可以通过使用copyWith方法来实现,例如:

floatingActionButton: new Theme(
        data: Theme.of(context).copyWith(accentColor: Colors.amber),
        child: FloatingActionButton(
          onPressed: _incrementCounter,
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),

Flutter Widget

无状态组件和有状态组件

Flutter将组件分为无状态和有状态两种。其中,无状态组件(StatelessWidget)是不可变的,这意味着它们的属性不能改变,所有的值都是最终的。有状态组件(StatefulWidget)持有状态可能在Widget生命周期中发生变化。

再平时开发中,使用得最多的应该就是有状态组件,要实现一个StatefulWidget至少需要两个类:

  • 一个StatefulWidget类,StatefulWidget类本身是不变的;
  • 一个State类,在Widget生命周期中始终存在。

例如,官方给出的示例就使用了有状态组件。

创建可重用组件

组件一般是在设计和实现阶段由一些类或者模块组成的群组。每个组件完成一个独立的功能, 并且都有一个和其它组件的良好接口。可重用组件是指通过对以往组件进行局部修改或者不修改就可以组成新的软件,可重用组件是可重用软件的基础。

在Flutter开发中,创建可重用组件的方式有很多,最简单就是通过参数的方式,创建一个可以重用的组件,例如:

// Flutter
class CustomCard extends StatelessWidget {
  CustomCard({@required this.index, @required 
     this.onPress});

  final index;
  final Function onPress;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        children: <Widget>[
          Text('Card $index'),
          FlatButton(
            child: const Text('Press'),
            onPressed: this.onPress,
          ),
        ],
      )
    );
  }
}

然后,在使用的时候,按照参数传入相应的值即可。

...
// Usage
CustomCard(
  index: index,
  onPress: () { 
    print('Card $index');
  },
)
    ...

资源管理

再原生应用开发过程中,Android和iOS都有特定的资源管理文件。虽然Android将resources 和 assets 区别对待,但在Flutter中它们都会被作为assets处理, 所有存在于Android上res / drawable- *文件夹中的资源都放在Flutter的assets文件夹中。

与Android类似,iOS 同样将 images 和 assets 作为不同的东西,而 Flutter 中只有 assets。被放到 iOS 中 Images.xcasset 文件夹下的资源在 Flutter 中被放到了 assets 文件夹中。

在Flutter开发中,assets 是资源文件的统一称呼,可以用来表示任意类型的文件,而不仅仅是图片。例如,你可以把 json 文件放置到 my-assets 文件夹中,将图片放到image文件中。

如果要访问 my-assets的文件,可以使用 AssetBundle 来访问它,如下所示:

import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;

Future<String> loadAsset() async {
  return await rootBundle.loadString('my-assets/data.json');
}

在原生Android开发中,我们将不同分辨率的图片放到不同的图片文件夹下,如下所示:

  • mipmap-ldpi 0.75x
  • mipmap-mdpi 1.0x
  • mipmap-hdpi 1.5x
  • mipmap-xhdpi 2.0x
  • mipmap-xxhdpi 3.0x
  • mipmap-xxxhdpi 4.0x

iOS 的图片则有1.0x,2.0x和3.0x之分,不同分辨率的手机会自动加载对应分辨率的图片。

对应FLutter图片来说,我们也可以参考这种规则,把1.0x的图片放到 images 文件夹,将2.0x
的图片放到另外的文件夹中,如下所示:

images/my_icon.png       // Base: 1.0x image
images/2.0x/my_icon.png  // 2.0x image
images/3.0x/my_icon.png  // 3.0x image

包管理

和原生Android和iOS应用开发一样,Flutter的第三方库文件都在pubspec.yaml文件中,如果要使用某个第三方库,可以打开包仓库地址进行搜索,如下图所示:
Flutter开发之基础知识
下面以依赖url_launcher第三方库为例,使用步骤如下:

1, 打开pubspec.yaml文件,在dependencies下添加包的名称和版本:

url_launcher: ^5.1.1

2,然后,点击Packages get命令来获取工程配置文件中的所添加的引用包,或者打开命令窗口执行flutter packages get命令,如下图:
Flutter开发之基础知识

3,然后,打开main.dart文件,导入url_launcher.dart包,并使用launch方法来打开url地址,如下所示:

import 'package:url_launcher/url_launcher.dart';

const url = "https://www.baidu.com";
launch(url);