flutter 实例 玩转flutter create 做倍程序员


//docs.flutter.dev/get-started/codelab
flutter create
可发布的应用要修改属性
1.应用Id
 com.dohonors.pinjianguan
2.应用名称
 品监官
3.应用图标
$ flutter create --org  com.dohonors  pinjianguan
To update to the latest version, run "flutter upgrade".
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
Creating project pinjianguan...
$ cd pinjianguan
$ flutter run
Your application code is in pinjianguan\lib\main.dart.


android\app\src\main\AndroidManifest.xml 的 package 字段
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.dohonors.pinjianguan">    
ios\prooject.pbxproj 中的PRODUCT_BUNDLE_IDENTIFIER字段
PRODUCT_BUNDLE_IDENTIFIER = com.dohonors.pinjianguan;
appId都是'com.dohonors.pinjianguan'


应用显示名称
不希望用户看到项目名称而是产品名称 如上面的 pinjianguan
android/app/src/main/AndroidManifest.xml
<application
android:label="品监官"
iOS
ios/Runner/Info.plist
<key>CFBundleDisplayName</key>
<string>品监官</string>
应用图标
项目目录运行flutter run
工程中应用图标
android\app\src\main\res
ios\Runner\Assets.xcassets\AppIcon.appiconset
更新flutter工程下所有图标
flutter_logo_updater your_logo_file_path_1024_logo.png  your_flutter_project_dir
$ flutter_logo_updater pinjianguan/images/logo_lxb.png  pinjianguan
扩展指定项目类型 指定项目模版创建工程的时候项目模版--sample指定项目模版
Dart代码在 /lib/main.dart
//book.flutterchina.club/chapter2/first_flutter_app.html#_2-1-2-首页


模板代码分析
1 导入包
import 'package:flutter/material.dart';
是导入 Material UI 组件库
Material是标准的移动端和web端的视觉设计语言 //material.io/guidelines
Flutter 默认丰富的 Material 风格的UI组件
2 应用入口
void main() => runApp(MyApp());
Flutter 应用 main 函数为应用程序的入口
main 函数调用runApp 方法 启动Flutter应用
runApp接受 Widget参数 MyApp对象
MyApp()是 Flutter 应用的根组件
runApp 是 Flutter 应用的入口
main函数使用了(=>)符号
Dart 单行函数或方法的简写
3 应用结构
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(  //应用名称  
  title: 'Flutter Demo',
  theme: ThemeData(    //蓝色主题  
    primarySwatch: Colors.blue,
  ), //应用首页路由  
  home: MyHomePage(title: 'Flutter Demo Home Page'),
);}}
MyApp类代表 Flutter 应用 继承StatelessWidget类
Flutter 大多数都是 widget 组件包括
对齐 Align
填充 Padding
手势处理 GestureDetector
等以 widget 形式提供
Flutter构建页面调用组件的build方法
widget 提供 build() 描述如何构建 UI
MaterialApp 是Material 库的 Flutter APP 框架设置应用的名称 主题 语言 首页及路由列表等
MaterialApp也是 widget
home 为 Flutter 应用的首页 是 widget
首页
1. 初识Widget
class MyHomePage extends StatefulWidget {
    MyHomePage({Key? key, required this.title}) : super(key: key);
    final String title;
    @override
    _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {}
MyHomePage 应用首页继承自StatefulWidget类
是有状态的组件 Stateful widget
有状态的组件Stateful widget  
无状态的组件Stateless widget
Stateful widget 有状态 widget 生命周期中可变
Stateless widget 不可变
Stateful widget 至少两个类组成 一个StatefulWidget类一个 State类
StatefulWidget类本身不变 State类 有的状态在 widget 生命周期中会变
_MyHomePageState类是MyHomePage类对应的状态类
和MyApp 类不同 MyHomePage 类中并没有build方法
取而代之的是build方法被挪到了_MyHomePageState方法中
3. State类
1) _MyHomePageState类
包含 组件的状态
int _counter = 0; //用于记录按钮点击的总次数
_counter 为保存屏幕右下角带 + 号按钮点击次数的状态
void _incrementCounter() {
setState(() {
 _counter++;
});
}
先自增_counter 后调用setState 方法
setState方法通知 Flutter 框架 有状态改变
Flutter 收到通知 执行 build 重新构建界面
Flutter 对此方法做了优化 重新执行很快 重新构建任何需要更新的东西 无需分别修改widget
构建UI界面的逻辑在 build 方法 MyHomePage第一次创建时
_MyHomePageState类被创建
初始化后 Flutter框架会调用 widget 的build 构建 widget 树 将 widget 树渲染到屏幕
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
  title: Text(widget.title),
),
body: Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      Text('You have pushed the button this many times:'),
      Text(
        '$_counter',
        style: Theme.of(context).textTheme.headline4,
      ),
    ],
  ),
),
floatingActionButton: FloatingActionButton(
  onPressed: _incrementCounter,
  tooltip: 'Increment',
  child: Icon(Icons.add),
),
);
}
Scaffold是 Material 库的脚手架
Scaffold默认导航栏 标题 包含主屏幕 widget 树组件树 或 部件树 的body属性
body的组件树中包含Center 组件 将其子组件树对齐到屏幕中心
Center子组件是个Column 组件将其子组件沿屏幕垂直方向排列
Column子组件是两个 Text
第一个显示固定文本 You have pushed the button this many times:
第二个显示_counter状态的数值
floatingActionButton 页面右下角的带 + 按钮
onPressed属性接受回调函数 _incrementCounter 处理函数
执行流程:
floatingActionButton按钮被点击调用_incrementCounter方法 先自增_计数器 后setState通知 Flutter框架状态变化
Flutter 框架调用build方法以新的状态重新构建UI最终显示在设备屏幕上


2 为什么 build 方法放在 State 中 不放在 StatefulWidget 中
为了开发灵活性
将build放在StatefulWidget有两个问题:
状态访问不便
如果StatefulWidget有很多状态而每次状态改变都要调用build方法
由于状态是保存在 State 中的如果build方法在StatefulWidget中
那么build方法和状态分别在两个类中那么构建时读取状态将会不方便
build在 StatefulWidget 中 由于构建用户界面过程需要依赖 State
所以build方法将必须加一个State参数
Widget build(BuildContext context, State state){}
只能将State的所有状态声明为公开的状态才能在State类外部访问状态
状态设置为公开将不再具有私密性
导致对状态的修改将会变的不可控
将build()方法放在State中的话构建过程不仅可以直接访问状态也无需公开私有状态
继承StatefulWidget不便
Flutter 中有一个动画 widget 的基类AnimatedWidget继承自StatefulWidget类
AnimatedWidget引入抽象方法build(BuildContext context)继承自AnimatedWidget的动画 widget 都要实现这个build方法
StatefulWidget 类中已经有build方法build方法需要接收一个 State 对象
AnimatedWidget必须将自己的 State 对象(记为_animatedWidgetState)提供给其子类
子类需要在其build方法中调用父类的build方法
class MyAnimationWidget extends AnimatedWidget{
Widget build(BuildContext context, State state){
  //由于子类要用到AnimatedWidget的状态对象_animatedWidgetState,
  //AnimatedWidget必须通过某种方式将其状态对象_animatedWidgetState  //暴露给其子类   
  super.build(context, _animatedWidgetState)
}}
不合理因为AnimatedWidget的状态对象是AnimatedWidget内部实现细节不应该暴露给外部
将父类状态暴露给子类必须有传递机制 而做这一套传递机制无意义
父子类之间状态的传递和子类本身逻辑是无关的
综上所述
对于 StatefulWidget将build方法放在 State 中 给开发带来很大的灵活性
open vscode
open main.dart
press F5 to run this pinjianguan project
好了到些 本文已经大功告成


官方帮助
$ flutter create --help
创建一个新的Flutter工程
If run on a project that already exists, this will repair the project, recreating any files that are missing.
如果在已经存在的项目上运行 这将修复项目 重新创建任何丢失的文件
Usage
flutter create <output directory>
-h, --help      Print this usage information.
--[no-]pub  Whether to run "flutter pub get" after the project has been created.
(defaults to on)项目创建后是否运行“flutter pub get (默认运行)
--[no-]offline When "flutter pub get" is run by the create command, this indicates whether to run it in offline mode or not. In offline mode, it will need to have all dependencies already available in the pub cache to succeed.
当经由创建命令运行“flutter pub get 时 是否在脱机模式下运行。在脱机模式下 需要pub缓存下面已经缓存了所有依赖。
--[no-]with-driver-test    Also add a flutter_driver dependency and generate a sample 'flutter drive' test.
添加flutter_driver依赖项 并生成一个示例“flutter driver依赖项 测试。
-t, --template=<type>Specify the type of project to create.
指定要创建的项目类型
[app] (default) Generate a Flutter application.
(默认)生成一个Flutter应用程序。
[module] Generate a project to add a Flutter module to an existing Android or iOS application.
生成一个项目 将一个Flutter模块添加到现有的Android或iOS应用程序。
[package] Generate a shareable Flutter project containing modular Dart code.
生成一个可复用的Dart包
[plugin] Generate a shareable Flutter project containing an API in Dart code with a platform-specific implementation for Android, for iOS code, or for both.
生成一个可复用的插件包 包括Dart代码及其对应的原生系统的相关的实现 这里的原生系统可以是iOS、android、或者两个都有。
-s, --sample=<id>  Specifies the Flutter code sample to use as the main.dart for an application.  --template=app. The value should be the sample ID of the desired sample from the API documentation website(http://docs.flutter.dev).
指定一套Flutter示例代码作为应用的main.dart。意味着--template=app。该值应该是来自API文档网站(http://docs.flutter.dev)的所需示例的示例ID
An example can be found at//master-api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html
--list-samples=<path>      Specifies a JSON output file for a listing of Flutter code samples that can created with --sample.
带——sample参数的的创建命令 有哪些可用的代码示例?用--list-samples=<path>指定一个JSON输出文件 可以列出这些代码示例。
--[no-]overwrite When performing operations, overwrite existing files.
--description  The description to use for your new Flutter project. This string ends up in the pubspec.yaml file.
(defaults to "A new Flutter project.")
--org The organization responsible for your new Flutter project, in reverse domain name notation. This string is used in Java package names and as prefix in the iOS bundle identifier.
(defaults to "com.example")
--project-name The project name for this new Flutter project. This must be a valid dart package name.
这个新的Flutter项目的项目名称
这必须是一个有效的dart包名
-i, --ios-language [objc, swift (default)]
-a, --android-language         [java, kotlin (default)]
--[no-]androidx Generate a project using the AndroidX support libraries
使用AndroidX support libraries生成一个项目
查看当前flutter通道版本
flutter channel
flutter channel stable|beta|dev|master。
查看通道是否切换成功
flutter channel或flutter doctor
flutter doctor --verbose
更新flutter和捆绑的dart到通道的最新版本
flutter upgrade
pubspec.yaml文件中#配置最小支持的版本会影响能用到的新语法多少
environment:
  sdk: ">=2.12.0 <3.0.0"
  flutter: ">=1.17.0"
Everything's a widget!
一切都是小部件但不要将所有东西放入widget
可读性
为布局的每个语义部分创建个小部件
每个小部件都有个较小的build方法易读无需滚动即可到达小部件的末尾
理解性
每个小部件都有个与其角色匹配的名称 称为语义命名
阅读代码容易在脑海中映射代码的哪一部分与在应用程序上看到的内容相匹配
可理解性方面的两个改进:
1. 阅读其他地方引用的此类小部件时 知道作用 无需看实现
2. 阅读有语义命名的小部件的构建方法前 对其内容有大致了解
维护性
更换组件只在一个地方 与其他小部件的其余部分分开不容易出错
在应用程序甚至另一个应用程序中的另一个页面中共享布局的一部分更加容易
提高应用程序的性能
因为每个小部件都可以与其他小部件分开重建当setState()在状态上调用时
所有后代小部件都将重建因此将setState()调用本地化到 UI 实际需要更改的子树部分
如果更改包含在树的一小部分请避免在树的高处调用 setState()
能const更频繁地使用关键字缓存和重新使用小部件
重用小部件比创建新的(但配置相同的 小部件要高效得多
提高工作效率
为布局的每个语义创建个小部件
在 Visual Studio Code 中使用Dart扩展提供的stless和stful片段
VS Code 必须遵循文档并添加以下内容
{
  "Flutter stateless widget": {
  "scope": "dart",
  "prefix": "sless",
  "description": "Insert a StatelessWidget",
  "body": [
   "class $1 extends StatelessWidget {",
   "  const $1({",
   "    Key key,",
   "  }) : super(key: key);",
   "",
   "  @override",
   "  Widget build(BuildContext context) {",
   "    return Container(",
   "      $2",
   "    );",
   "  }",
   "}"
  ]
 },
 "Flutter stateful widget": {
  "scope": "dart",
  "prefix": "sful",
  "description": "Insert a StatefulWidget",
  "body": [
   "class $1 extends StatefulWidget {",
   "  const $1({",
   "    Key key,",
   "  }) : super(key: key);",
   "",
   "  @override",
   "  _$1State createState() => _$1State();",
   "}",
   "",
   "class _$1State extends State<$1> {",
   "  @override",
   "  Widget build(BuildContext context) {",
   "    return Container(",
   "      $2",
   "    );",
   "  }",
   "}"
  ]
 },
}
编写 Flutter 应用程序的好方法
Everything’s a widget but don’t put everything in one widget


Flutter 实例和flutter-example相关