Flutter入门概览1-Flutter篇
本系列文章共有三篇,计划分别从Flutter、Dart、工具三个方面介绍,快速形成对Flutter开发的一个综合概念。
本文主要介绍Flutter相关知识。
Flutter语言使用 Dart,开发IDE使用VSCode、Android Studio 或 IntelliJ IDEA,个人推荐使用VSCode。
Flutter概览
Flutter是由Google开发的开源移动应用开发框架,用于快速构建高性能、高保真度的跨平台移动应用。Flutter支持同一套代码在 iOS、Android、Web、桌面应用等多个平台上运行,使用自带的 Skia 图形引擎,可以直接绘制 UI 组件,这使得 Flutter 应用在性能方面表现出色,滚动流畅,响应迅速(目前正在使用 Impeller 替换 Skia)。
Flutter架构
看一眼有个印象即可。
参考资料
三棵树
Flutter的渲染机制由三棵树组成:Widget Tree、Element Tree、Render Tree(渲染树)。
- 所有Widget组成Widget Tree。
- 通过调用Widget的
createElement()
方法,创建Element Tree,Wdiget Tree与Element Tree是一一对应的。 - 每个Element调用
createRenderObject()
形成Render Tree,Render Tree负责渲染,注意Render Tree与Elemeng Tree并不是一一对应的,而是为最后渲染做准备。
Widget
在Flutter中,widget是一个非常重要的概念,是描述UI的基本元素。可以用iOS中的UIView来类比理解widget的概念,但是widget并不是UIView。widget只是对布局的一种描述,最终还要经过三棵树生成element和renderObject才会被绘制到屏幕上,而UIView就是最终渲染的view。
这里可以给出一个widget的定义:widget是Flutter中描述一UI元素的配置信息,需要经过三棵树生成最终的renderObject才会被渲染到屏幕上。可以用UIView理解,但是UIView更像renderObject。
在Flutter中,通过widget嵌套widget的方式来构建UI和进行事件处理,所以万物都是Widget。Widget的基类是Widget
,是一个抽象类一般不会直接用。
在flutter中,widget分为两类:有状态的widget和无状态的widget,即StatefulWidget
和StatelessWidget
,两个都直接继承自Widget
类。不需要改变的元素使用StatelessWidget
,设定好后元素不会被改变;需要改变的元素需要使用 StatefulWidget
,通过改变内部state来修改自身UI,触发重新渲染。
StatelessWidget
,无状态widget,设定好后不能再修改。StatefulWidget
,有状态的widget,内部会对应一个State类,通过修改State可以改变自身widget,然后更新UI。
参考:
- Widget 简介 - Flutter实战第二版
StatelessWidget
StatelessWidget是无状态组件,通过build
方法来构建UI。
build
,通过build方法嵌套其他widget来构建UI,在构建过程中会递归的构建其他嵌套的widget。context
,build
方法有一个context
参数,它是BuildContext
类的一个实例,表示当前 widget 在 widget 树中的上下文,每一个 widget 都会对应一个 context 对象(因为每一个 widget 都是 widget 树上的一个节点)。实际上,context
是当前 widget 在 widget 树中位置中执行”相关操作“的一个句柄(handle),比如它提供了从当前 widget 开始向上遍历 widget 树以及按照 widget 类型查找父级 widget 的方法。
// StatelessWidget 定义
abstract class StatelessWidget extends Widget {
const StatelessWidget({ super.key });
@override
StatelessElement createElement() => StatelessElement(this);
// 核心是 build 方法
@protected
Widget build(BuildContext context);
}
// 示例,Echo widget,核心是build方法构建UI
class Echo extends StatelessWidget {
const Echo({
Key? key,
required this.text,
this.backgroundColor = Colors.grey, //默认为灰色
}):super(key:key);
final String text;
final Color backgroundColor;
@override
Widget build(BuildContext context) {
return Center(
child: Container(
color: backgroundColor,
child: Text(text),
),
);
}
}
// 在子树中获取父级widget的一个示例:
class ContextRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Context测试"),
),
body: Container(
child: Builder(builder: (context) {
// 在 widget 树中向上查找最近的父级`Scaffold` widget
Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();
// 直接返回 AppBar的title, 此处实际上是Text("Context测试")
return (scaffold.appBar as AppBar).title;
}),
),
);
}
}
StatefulWidget
StatefulWidget的核心就是有状态,可以修改重绘UI。
- StatefulWidget重写了createElement方法,返回的是
StatefulElement
,StatefulElement
可能会多次调用createState()
来创建对象。 createState()
,创建状态,修改UI必须通过修改状态来实现,一个StatefulElement
对应一个State
实例。
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
@override
StatefulElement createElement() => StatefulElement(this);
@protected
State createState();
}
State
一个StatefulWidget类会对应一个State类,State表示与其对应的StatefulWidget要维护的状态。
State中的状态信息:
- 在 widget 构建时可以被同步读取。
- 在 widget 生命周期中可以被改变,当State被改变时,可以手动调用其
setState()
方法通知Flutter 框架状态发生改变,Flutter 框架在收到消息后,会重新调用其build
方法重新构建 widget 树,从而达到更新UI的目的。
State中有两个常用的信息:
widget
,它表示与该 State 实例关联的 widget 实例,由Flutter 框架动态设置。注意,这种关联并非永久的,因为在应用生命周期中,UI树上的某一个节点的 widget 实例在重新构建时可能会变化,但State实例只会在第一次插入到树中时被创建,当在重新构建时,如果 widget 被修改了,Flutter 框架会动态设置State. widget 为新的 widget 实例。context
。StatefulWidget对应的 BuildContext,作用同StatelessWidget 的BuildContext。
State生命周期:
这块详细参考:State-Flutter实战第二版
参考资料
- Widget 简介 - Flutter实战第二版
布局
Debugger输出
- debugPrint
- log
// debugPrint
import 'package:flutter/foundation.dart';、
debugPrint('movieTitle: $movieTitle');
// log
import 'dart:developer'; //(auto import will do this even)
//example for api logging
log("${response?.statusCode} : ${response?.request?.path}",
name: "Response", error: response.data);
Flutter命令
// 检测flutter配置,输出相关依赖的安装情况
flutter doctor
// flutter 工程安装依赖,注意针对flutter工程,需要使用flutter命令(dart pub get是针对dart工程)
flutter pub get
// flutter 工程添加依赖
flutter pub add css_colors
// flutter 移除依赖
flutter pub remove css_colors
// 运行flutter工程
flutter run
// Other
// 升级Flutter SDK
flutter upgrade
// 创建Flutter App
flutter create test_drive // 创建Flutter工程模板
flutter devices // 选择对应的平台
flutter run // 运行Flutter工程
// 后续注意使用 fvm flutter 代替 flutter
# Use
> fvm flutter {command}
# Instead of
> flutter {command}
// 后续使用 fvm dart 代替 dart
# Use
> fvm dart {command}
# Instead of
> dart {command}
创建Flutter工程
具体参考:开发体验初探
通过VSCode创建Flutter App:
- 打开VSCode命令窗口,输入Flutter,选择
Flutter: New Project
- 通过命令行创建 :flutter create -t app
Flutter工程结构目录
工程结构
创建工程后,默认会显示以下文件
.
├── .dart_tool # 记录了一些dart工具库所在的位置和信息
├── .idea # android studio 是基于idea开发的,.idea 记录了项目的一些文件的变更记录
├── android # Android项目文件夹
├── build # 编译或运行后产物
├── ios # iOS项目文件夹
├── lib # lib文件夹存放我们的dart语言代码
├── linux # Linux项目目录
├── macos # mac项目目录
├── test # 测试代码
├── web # web项目目录
├── windows # win项目目录
├── .gitignore # git忽略配置文件
├── .metadata # 一个对当前workspace的配置记录
├── analysis_options.yaml # flutter lint配置文件,定义代码静态分析相关的配置项和规则
├── flutter_application_1.iml # 工程文件的本地路径配置,在Android Studio或IntelliJ下起作用
├── pubspec.lock # 项目依赖的lock文件
├── pubspec.yaml # 依赖配置文件,类似package.json文件
└── README.md # README
其中比较关注以下几个文件夹:
- lib,存放工程的核心代码
- pubspec.yaml,依赖配置管理
另外,一般额外创建两个目录:assets
和fonts
,用于存放图片和字体,注意需要在pubspec.yaml
文件中声明。
# 示例
# The following section is specific to Flutter.
flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/
fonts:
- family: Raleway
fonts:
- asset: fonts/Raleway-Regular.ttf
- asset: fonts/Raleway-Italic.ttf
style: italic
- family: RobotoMono
fonts:
- asset: fonts/RobotoMono-Regular.ttf
- asset: fonts/RobotoMono-Bold.ttf
weight: 700
lib目录结构
不要一直寻求最佳实践,最佳实践只是最小省力原则,要 go above and beyond。
lib目录是存放了我们工程代码,结合前端工程,目前得出一个最佳目录结构。
lib
├── main.dart
├── api # 接口请求
├── components # 公共组件
├── l10n # 国际化,Flutter中使用 flutter_localizations 库作为国际化,因此叫l10n
├── router # 路由
├── store # 状态管理
├── models # Json文件对应的Dart Model类会在此目录下
├── types # 公共类型定义
├── utils # 工具函数、通用方法、网络接口
└── pages # 页面
参考:
- A Comprehensive Guide to Creating a Scalable Folder Structure for Flutter Apps
- Flutter APP代码结构 - Flutter实战第二版
- 三步入门之Flutter一看工程目录结构设计
pubspec.yaml文件
参考资料
常用三方库
功能类
- dio,网络库
- shared_preferences,存储库
- flutter_ume,字节开源的debug库
- flutter_ume_plus,ume目前看不再维护,需要使用该库
- event_bus_plus,Flutter的 EventBus,订阅发布机制,用于不同模块之间通信
- device_info_plus,获取设备信息,品牌/系统/屏幕等等
- fl_chart,Flutter图表库,效果示例
- skeletonizer,骨架屏
- bot_toast,toast库
- cached_network_image,网络图片缓存
- flutter_animate,强大的动画库
- flame,flutter游戏框架,使用该框架开发手机游戏
- go_router,flutter官方出的路由框架
- permission_handler,封装了iOS/Anroid权限管理库
- easy_refresh,上拉下拉加载刷新库
- fluttertoast,Toast库
- pretty_qr_code,二维码生成库
- url_launcher,支持scheme url跳转第三方应用
- path_provider,获取系统文件路径
- bruno,贝壳维护的一套Flutter UI组件库
- FAIR,58维护的一套动态化框架,
工具类
学习Demo
- Flutter Gallery - 官方,Flutter官方示例工程
- Flutter Samples - 官方,官方示例工程页面,集成了一些项目参考
- flutter_flexible,一个集成了常用的第三方工程
FlutterUnit
FlutterUnit是一个非常强大的Flutter学习利器,提供全面的Flutter学习指南,支持iPhone/Andriod/Mac/PC全平台,可以快速查看组件API说明和示例。可以说是学习Flutter的必备学习软件。
Flutter源码中的可用的组件一共350个左右,纷繁复杂,也没有明确的分类标准 FlutterUnit 对
大大小小,常用不常用
的组件能收的尽量收录。并根据个人感觉进行评星
目前收录组件306个
,每个都有至少一个演示展现和代码展示。
FlutterUnit提供以下功能:
- 300+组件的收录
- 组件详情说明,提供组件的属性和说明演示
- 可操作,操作交互类组件提供可操作性
- 提供组件的关联切换
Material Design
是一种用户界面设计语言,开始被Google引入用于安卓的UI设计风格。现在提供一系列UI组件,Flutter核心的UI库。
参考资料:
- Material Design - 官网
- Material Icons - 官网
参考资料
转载自:https://juejin.cn/post/7376937268215463975