之前一直不是太想学手机端的开发,一直希望有一款实用的linux手机,但即贵且不实用,还没有保障。根本达不到商用。
个人对手机端开发是有需求的。通过手机端,可以实现很多想法。前端手机,后端Golang,世界就更大了。
禁不住诱惑,决定花点时间学习Flutter和Dart。以下是学习中的整理。接下来会有更多的学习文章。
题外话:建立了几个Demo,几个G就没有,平均每个项目的build目录占用600MB。这是编译后的apk等,删除!节约点我的SSD。
资源
Flutter 中文开发者
Flutter中文网
Flutter实战·第二版
Flutter实用插件集录
Flutter 中文文档
布局工具
对于懒鬼,每次都flutter run也是很麻烦的。修改一下flutter.bat,改名为f.bat,或者重建一个f.bat文件。
@ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%i IN ("%~dp0..") DO SET FLUTTER_ROOT=%%~fi
REM If available, add location of bundled mingit to PATH
SET mingit_path=%FLUTTER_ROOT%\bin\mingit\cmd
IF EXIST "%mingit_path%" SET PATH=%PATH%;%mingit_path%
REM Test if Git is available on the Host
where /q git || ECHO Error: Unable to find git in your PATH. && EXIT /B 1
REM Test if the flutter directory is a git clone, otherwise git rev-parse HEAD would fail
IF NOT EXIST "%flutter_root%\.git" (
ECHO Error: The Flutter directory is not a clone of the GitHub project.
ECHO The flutter tool requires Git in order to operate properly;
ECHO to set up Flutter, run the following command:
ECHO git clone -b stable https://github.com/flutter/flutter.git
EXIT 1
)
REM Include shared scripts in shared.bat
SET shared_bin=%FLUTTER_ROOT%\bin\internal\shared.bat
CALL "%shared_bin%"
SET flutter_tools_dir=%FLUTTER_ROOT%\packages\flutter_tools
SET cache_dir=%FLUTTER_ROOT%\bin\cache
SET snapshot_path=%cache_dir%\flutter_tools.snapshot
SET dart_sdk_path=%cache_dir%\dart-sdk
SET dart=%dart_sdk_path%\bin\dart.exe
IF "%1"=="" (
"%dart%" --disable-dart-dev --packages="%flutter_tools_dir%\.packages" %FLUTTER_TOOL_ARGS% "%snapshot_path%" run & exit /B !ERRORLEVEL!
) ELSE (
"%dart%" --disable-dart-dev --packages="%flutter_tools_dir%\.packages" %FLUTTER_TOOL_ARGS% "%snapshot_path%" %* & exit /B !ERRORLEVEL!
)
默认没有参数时,直接run。即我要运行flutter时,直接使用命令f即可。
学习Flutter和Dart
目前 Flutter 已经支持 iOS、Android、Web、Windows、macOS、Linux、Fuchsia
AOT (Ahead of time)即 “提前编译”
JIT(Just-in-time)即“即时编译”
安装
export PUB_HOSTED_URL=https://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
Flutter SDK下载地址:https://flutter.dev/docs/development/tools/sdk/releases
检查运行环境:flutter doctor
升级Flutter SDK和依赖包:flutter upgrade
Dart
dynamic 意思是数据类型是动态可变的,不同于var,var定义后就不能改变数据类型。
Object Dart的所有东西都继承自Object,因此Object可以定义任任何变量,且赋值后,类型也可以更改
一般可用Object代替dynamic
final 常量,当类创建时才初始化。
const 编译时常量,即在编译时就初始化了。
类型类型:
List 列表
Set
Map 字典
Runes Unicode字符串
可选命名参数 {} 位置可以不一致,通过关键字传送
bool say(String msg, {String from, int color}) {
return true;
}
调用示例: say('Hello', from:'Ease');
这里的from和color是可选参数
可选位置参数 []
可选参数必须按顺序赋值
bool say(String msg, [String from, int clock]){
return true;
}
调用示例:
say(‘Hello’)
say(‘Hello’,‘Ease’,1)
say(‘Hello’,‘Ease’)
say(‘Hello’,1) // 错误
可选参数的默认值 =
bool say(String msg, {String from='ease', int color=0}){
return true;
}
箭头语法 =>
语句后⾯只能跟⼀⾏代码,⽽且这⼀⾏代码只能⼀个表达式,⽽不能跟语句
例如:void main() => runApp(MyApp());
等价于:
void main(){
return runApp(MyApp());//runApp() 返回的是 void
}
操作符
/ 精确除法
~/ 整除
% 取余
++var
var++
–var
var–
条件运算符
condition ? expr1 : expr2
expr1 ?? expr2 如果expr1为null,就返回expr2的值,否则返回expr1的值。
级联操作符
..
- StatelessWidget:无状态信息的 Widget
- StatefulWidget:有状态信息的 Widget
就象HelloWorld一样,先看看最简Flutter程序
import 'package:flutter/material.dart';
void main() {
runApp(const Center(
child: Text(
"您好!",
textDirection: TextDirection.ltr,
),
));
}
在一个黑漆漆的背景下,一个孤零零的"您好"。
注意:如果没有textDirection属性,将显示一个出错信息:No Directionality widget found
为了更符合“现代”编程,将其“类”化
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
"您好!",
textDirection: TextDirection.ltr,
),
);
}
}
继续完善,添加一个标题,定义外观样式
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp( // 标准的框架组件
home: Scaffold(
appBar: AppBar(title: const Text("演示")), // 设置标题
body: const Center(
child: Text(
"您好!",
textDirection: TextDirection.ltr,
style: TextStyle(color: Color.fromARGB(255, 100, 200, 1), fontSize: 23), // 定义了颜色和字大小
),
)),
theme: ThemeData.light(), // 组件已有几种样式
);
}
}
全屏应用,把右上角的DEBUG也去掉
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); // 全屏
return MaterialApp(
debugShowCheckedModeBanner: false, // 不显示右上角DEBUG图标
home: Scaffold(
appBar: AppBar(title: const Text("演示")),
body: const Center(
child: Text(
"您好!",
textDirection: TextDirection.ltr,
style: TextStyle(color: Color.fromARGB(255, 100, 200, 1), fontSize: 23),
),
)),
theme: ThemeData.light(),
);
}
}
Material框架的应用
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter框架学习',
home: Scaffold(
appBar: AppBar(
title: const Text("框架学习"),
),
body: const Center(
child: Text("框架学习内容"),
)));
}
}
非Material框架的应用
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(color: Colors.white),
child: const Center(
child: Text(
'非Material框架的应用',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 17,
color: Colors.black38,
),
),
),
);
}
}
Row: 几列 Column: 几行 Stack: Container:
mainAxisAlignment 主轴对齐方式
crossAxisAlignment 交叉轴对齐方式
mainAxisAlignment: MainAxisAlignment.spaceEvenly 空间均分
居中,通过Expanded让图片适用框架大小
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
Container 向组件添加边界、背景色等装饰
GridView 将组件展示为一个可滚动网格
ListView 将组件展示为一个可滚动的列表
Stack 将组件覆盖在另一个的上面
查看布局:
import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
debugPaintSizeEnabled = true;
添加资源和图片
pubspec.yaml
flutter:
assets:
- assets/my_icon.png
- assets/background.png
或者包含目录下所有
flutter:
assets:
- directory/
- directory/subdirectory/
加载 assets
加载文本
加载图片
return const Image(image: AssetImage(‘graphics/background.png’));
return const AssetImage(‘icons/heart.png’, package: ‘my_icons’);
// 延时运行 Future.delayed(const Duration(milliseconds: 2000), () { … });
添加启动闪屏
- 在AndroidMainifest.xml中添加
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
- 在launch_background.xml中添加
<item>
<bitmap
android:gravity="center"
android:scaleType="center"
android:src="@mipmap/ic_launcher" />
</item>
这里就定义了启动画面为资源文件夹下的ic_launcher.png图片
注意:这里的 launch_background.xml 修改涉及到两处,一处是在drawable目录下 ,一处是在drawable-v21目录下,否则不出效果