包含 Flutter 常用的组件、布局、方法等。初学者的完整快速参考
$ sudo softwareupdate --install-rosetta --agree-to-license
在 Apple 芯片的 Mac 电脑 上,还需要安装 Rosetta 2 环境因为 一些辅助工具 仍然需要,通过手动运行上面的命令来安装
安装包来获取最新的 stable Flutter SDK:
Apple 芯片 flutter_macos_arm64_3.3.8-stable.zip
想要获取到其他版本的安装包,请参阅 SDK 版本列表 页面
将文件解压到目标路径, 比如:
$ cd ~/development
$ unzip ~/Downloads/flutter_macos_3.3.8-stable.zip
配置 flutter 的 PATH 环境变量:
$ export PATH="$PATH:`pwd`/flutter/bin"
运行 flutter doctor 命令
flutter 目录整个放在你想放置 Flutter SDK 的路径中(例如 C:\src\flutter)path 环境变量,在开始菜单的搜索功能键入「env」,然后选择 编辑系统环境变量。在 用户变量 一栏中,检查是否有 Path 这个条目:
; 分隔已有的内容,加入 flutter\bin 目录的完整路径。flutter\bin 所在的完整路径作为新变量的值如果你不想安装指定版本的安装包。可以忽略步骤 1 和 2。从 GitHub 上的 Flutter repo 获取源代码,并根据需要,切换到指定的分支或标签
C:\src>git clone https://github.com/flutter/flutter.git -b stable
Text("Hello world",
  textAlign: TextAlign.left,
);
Text("Hello world! I'm Jack. "*4,
  maxLines: 1,
  overflow: TextOverflow.ellipsis,
);
Text("Hello world",
  textScaleFactor: 1.5,
);
Text("Hello world",
  style: TextStyle(
    color: Colors.blue,
    fontSize: 18.0,
    height: 1.2,  
    fontFamily: "Courier",
    background: Paint()..color=Colors.yellow,
    decoration:TextDecoration.underline,
    decorationStyle: TextDecorationStyle.dashed
  ),
);
Text.rich(TextSpan(
    children: [
     TextSpan(
       text: "Home: "
     ),
     TextSpan(
       text: "https://flutter.dev",
       style: TextStyle(
         color: Colors.blue
       ),  
       recognizer: _tapRecognizer
     ),
    ]
))
DefaultTextStyle(
  // 1.设置文本默认样式  
  style: TextStyle(
    color:Colors.red,
    fontSize: 20.0,
  ),
  textAlign: TextAlign.start,
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      Text("hello world"),
      Text("I am Jack"),
      Text("I am Jack",
        style: TextStyle(
          inherit: false, //2.不继承默认样式
          color: Colors.grey
        ),
      ),
    ],
  ),
);
在 asset 中声明,要先在 pubspec.yaml 中声明它
flutter:
  fonts:
    - family: Raleway
      fonts:
        - asset: assets/fonts/Raleway-Regular.ttf
        - asset: assets/fonts/Raleway-Medium.ttf
          weight: 500
        - asset: assets/fonts/Raleway-SemiBold.ttf
          weight: 600
    - family: AbrilFatface
      fonts:
        - asset: assets/fonts/abrilfatface/AbrilFatface-Regular.ttf
将字体文件复制到在 pubspec.yaml 中指定的位置
使用字体
// 声明文本样式
const textStyle = const TextStyle(
  fontFamily: 'Raleway',
);
// 使用文本样式
var buttonText = const Text(
  "Use the font for this text",
  style: textStyle,
);
ElevatedButton(
  child: Text("normal"),
  onPressed: () {},
);
TextButton(
  child: Text("normal"),
  onPressed: () {},
)
OutlineButton(
  child: Text("normal"),
  onPressed: () {},
)
IconButton(
  icon: Icon(Icons.thumb_up),
  onPressed: () {},
)
ElevatedButton.icon(
  icon: Icon(Icons.send),
  label: Text("发送"),
  onPressed: _onPressed,
),
OutlineButton.icon(
  icon: Icon(Icons.add),
  label: Text("添加"),
  onPressed: _onPressed,
),
TextButton.icon(
  icon: Icon(Icons.info),
  label: Text("详情"),
  onPressed: _onPressed,
),
在工程根目录下创建一个images目录,并将图片 aaa.png 拷贝到该目录。
在 pubspec.yaml 中的 flutter 部分添加如下内容:
assets:
  - images/aaa.png
注意: 由于 yaml 文件对缩进严格,所以必须严格按照每一层两个空格的方式进行缩进,此处 assets 前面应有两个空格。
加载该图片
Image(
  image: AssetImage("images/aaa.png"),
  width: 100.0
);
Image 也提供了一个快捷的构造函数 Image.asset 用于从 asset 中加载、显示图片:
Image.asset("images/aaa.png",
  width: 100.0,
)
Image(
  image: NetworkImage(
      "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
  width: 100.0,
)
Image 也提供了一个快捷的构造函数 Image.network 用于从网络加载、显示图片:
Image.network(
  "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
  width: 100.0,
)
const Image({
  ...
  this.width, // 图片的宽
  this.height, // 图片高度
  this.color, // 图片的混合色值
  this.colorBlendMode, // 混合模式
  this.fit,// 缩放模式
  // 对齐方式
  this.alignment = Alignment.center,
  // 重复方式
  this.repeat = ImageRepeat.noRepeat,
  ...
})
Switch(
  value: true,//当前状态
  onChanged:(value){
    // 重新构建页面  
  },
),
Checkbox(
  value: true,
  // 选中时的颜色
  activeColor: Colors.red,
  onChanged:(value){
    // ...
  },
)
TextField(
    autofocus: true,
    onChanged: (v) {
      print("onChange: $v");
    }
)
模糊进度条(会执行一个动画)
LinearProgressIndicator(
  backgroundColor: Colors.grey[200],
  valueColor: AlwaysStoppedAnimation(Colors.blue),
),
进度条显示 50%
LinearProgressIndicator(
  backgroundColor: Colors.grey[200],
  valueColor: AlwaysStoppedAnimation(Colors.blue),
  value: .5, 
)
模糊进度条(会执行一个旋转动画)
CircularProgressIndicator(
  backgroundColor: Colors.grey[200],
  valueColor: AlwaysStoppedAnimation(Colors.blue),
),
进度条显示 50%,会显示一个半圆
CircularProgressIndicator(
  backgroundColor: Colors.grey[200],
  valueColor: AlwaysStoppedAnimation(Colors.blue),
  value: .5,
),
线性进度条高度指定为 3
SizedBox(
  height: 3,
  child: LinearProgressIndicator(
    backgroundColor: Colors.grey[200],
    valueColor: AlwaysStoppedAnimation(Colors.blue),
    value: .5,
  ),
),
圆形进度条直径指定为 100
SizedBox(
  height: 100,
  width: 100,
  child: CircularProgressIndicator(
    backgroundColor: Colors.grey[200],
    valueColor: AlwaysStoppedAnimation(Colors.blue),
    value: .7,
  ),
),
在实际开发中,Container常常用于对一个组件进行包装修饰。
Container(
  width: 100,
  height: 100,
  color: Colors.blue,
  alignment: Alignment.center,
  child: Text('Hello world'),
),
将 Contianer 大小固定为 100 * 100, 背景色为蓝色。把 Text 包裹在 Container 中,并将其居中
列布局(Column),可以将多个子组件沿着垂直的方向摆放(竖的摆放)
// 将container 和 button 摆放到同一列。
Column(
   children: [
     Container(
       width: 100,
       height: 100,
       color: Colors.blue,
       alignment: Alignment.center,
       child: Text('Hello world'),
     ),
     ElevatedButton(
       onPressed: () {},
       child: Text('Button'),
     ),
   ],
),
行布局(Row),可以将多个组件沿水平的方向摆放。
Row(
  children: [
    ElevatedButton(
      onPressed: () {},
      child: const Text('1'),
    ),
    ElevatedButton(
      onPressed: () {},
      child: const Text('2'),
    ),
    ElevatedButton(
      onPressed: () {},
      child: const Text('3'),
    ),
  ],
),
在同一行摆放 3 个 Button
将子组件从左到右依次排列,当空间不足时自动换行。
Wrap(
  children: [
    FlutterLogo(),
    FlutterLogo(),
    FlutterLogo(),
    FlutterLogo(),
    FlutterLogo(),  
    FlutterLogo(),
  ],
),
显示多个 Flutter 的 logo 并自动换行
Stack 可以将一多个子组件叠在一起显示。堆叠顺序按照children属性中的列表依次堆叠摆放,默认将子控件沿左上角对齐。
需要控制子控件位置可以嵌套Positoned控件。
Stack(
  children: [
    Container(
      height: 300,
      width: 300,
      color: Colors.blue,
    ),
    Container(
      height: 200,
      width: 200,
      color: Colors.black,
    ),
    Container(
      height: 100,
      width: 100,
      color: Colors.yellow,
    ),
  ],
),
依次堆叠 300*300 的蓝色色块、200*200 的黑色色块、100*100 的黄色色块
若需要控制Stack中子控件的位置,则可以嵌套改控件。
Stack(
  children: [
    // 默认摆放在左上位置
    Container(
      height: 300,
      width: 300,
      color: Colors.blue,
    ),
    // 距离左边40个、距离上面40个逻辑像素的位置
    Positioned(
      left: 40,
      top: 40,
      child: Container(
        height: 200,
        width: 200,
        color: Colors.black,
      ),
    ),
    // 距离左边80个、距离上面80个逻辑像素的位置
    Positioned(
      left: 80,
      top: 80,
      child: Container(
        height: 100,
        width: 100,
        color: Colors.yellow,
      ),
    ),
  ],
),
Align组件用于决定子组件对齐方式
// 使用Align将Button 居中在Container中
Container(
  width: 100,
  height: 100,
  color: Colors.green,
  child: Align(
    alignment: Alignment.center,
    child: ElevatedButton(
      onPressed: () {}, 
      child: Text('Center'),
    ),
  ),
),
Center 组件实际上继承于Align。用于专门剧中。
//与 Align中代码效果一致
Container(
  width: 100,
  height: 100,
  color: Colors.green,
  child: Center(
    child: ElevatedButton(
      onPressed: () {}, 
      child: Text('Center'),
    ),
  ),
),
Flex 的用法与 Row 或 Column 类似,但只需要额外传入 direction 参数
Row 和 Column 组件都继承 Flex 组件direction 为 Axis.horizontal 表示水平方向(Row),为 Axis.vertical则为垂直方向(Column)垂直方向依次摆放3个flutter logo
Flex(
  direction: Axis.vertiacl,
  children: [
    FlutterLogo(),
    FlutterLogo(),
    FlutterLogo(),
  ],
),
水平方向依次摆放 3 个 flutter logo
Flex(
  direction: Axis.horizontal,
  children: [
    FlutterLogo(),
    FlutterLogo(),
    FlutterLogo(),
  ],
),
Expanded 用于扩张一个子组件。可以通过 flex 属性,用于表示该组件相对其他弹性组件放大的倍数(可以理解为一个权重)。
// Container 会占满剩余的全部空用空间
Row(
  children: [
    FlutterLogo(),
    Expanded(
      child: Container(
        child: FlutterLogo(),
        color: Colors.green,
      ),
    ),
    FlutterLogo(),
  ],
),
// 按照1:2 的比例分配一整行的空间
Row(
  children: [
    Expanded(
      flex: 1,
      child: Container(
        child: FlutterLogo(),
        color: Colors.green,
      ),
    ),
    Expanded(
      flex: 2,
      child: Container(
        child: FlutterLogo(),
        color: Colors.blue,
      ),
    ),
  ],
),
Flexible 是 Expanded 组件的父类。
与 Expanded 不同的是,Flexible 可以通过 fit 属性设置子控件是否必须占满 Flexibal 扩展的空间。而 Expaned 默认子控件必须占满
// 如果将fit设置为tight,
// 则绿色Container 和蓝色Container大小一样。
// 如果将fit设置为loose,
// 则两个Flexible扩展的空间大小是一样的,
// 但绿色Container并不会填充整个扩展的空间。
Row(
  children: [
    Flexible(
      flex: 2,
      // fit: FlexFit.tight,
      child: Container(
        child: FlutterLogo(),
        color: Colors.green,
      ),
    ),
    Expanded(
      flex: 2,
      child: Container(
        child: FlutterLogo(),
        color: Colors.blue,
      ),
    ),
  ],
),
将 Flexible 的 fit 属性设置为 tingt,就等价于使用 Expanded
Spacer 用于在布局中留白
Row(
  children: [
    Text('Item'),
    Spacer(),
    FlutterLogo(),
  ],
),
例如,需要文本和图标位于一个行的两端,而中间留白时。就可以使用 Spacer
ListView 是一个支持滚动的列表组件。该组件默认支持上下滑动。
ListView的默认构造函数,会立即初始化children中的所有子widget,无法动态加载。
ListView(
  children: [
    Text('1'),
    Text('2'),
    Text('3'),
    Text('4'),
  ],
),
需要动态加载,则可以使用 ListView.builder()命名构函数。
// 动态生成4个Text
ListView.builder(
  itemBuilder: (BuildContext context, int index) {
    return Text('$index');
  },
  itemCount: 4,
),
需要在对ListView中的Item添加分割线,则可以借助ListView.separated()。
// separatorBuilder 函数用于在元素之间插入分割线。
// 也可以返回其他widget。该widget会被插入各个元素之间。
ListView.separated(
  itemBuilder: (BuildContext context, int index) {
    return Text('$index');
  },
  itemCount: 4,
  separatorBuilder: (BuildContext context, int index) {
    // 使用Divider widget 画一条粗为5,颜色为红色的线
    return const Divider(
      height: 5,
      thickness: 5,
      color: Colors.red,
    );
  },
),
GridView可将元素显示为二维网格状的列表组件,并支持主轴方向滚动。
使用GridView() 构造函数,需要传入gridDelegate和children。Flutter中已经提供了两种实现方式,分别是:
SliverGridDelegateWithFixedCrossAxisCount() 用于交叉轴方向固定数。SliverGridDelegateWithMaxCrossAxisExtent() 用于交叉轴方向限制最大长度。// 使用SliverGridDelegateWithFixedCrossAxisCount
GridView(
  gridDelegate:
      const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4),
  children: List.generate(
      8,
      (index) => Container(
            color: Colors.red[index % 8 * 100],
            child: Text("index $index"),
          )),
),
// 使用SliverGridDelegateWithMaxCrossAxisExtent
 GridView(
  gridDelegate:
      SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 200),
  children: List.generate(
    8,
    (index) => Container(
      color: Colors.red[index % 8 * 100],
      child: Text("index $index"),
    ),
  ),
),
GridView.builder()命名构造可以实现元素的动态加载,与ListView.builder()类似
GridView.builder(
  itemCount: 8,
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 4),
  itemBuilder: (context, index) => Container(
    color: Colors.red[index % 8 * 100],
    child: Text("index $index"),
  ),
),
Gridview.count() 一个简单的构造函数,只需要传入crossAxisCount(交叉轴元素的个数)和children即可。
GridView.count(
  crossAxisCount: 4, // 每行固定为4个
  children: List.generate(
      8,
      (index) => Container(
            color: Colors.red[index % 8 * 100],
            child: Text("index $index"),
          )),
),
GridView.extent() 用于设定每个元素在交叉轴方向的最大尺寸。当程序运行在较大屏幕时通常能看到更多的元素,而不是少量元素的放大版。通过传入maxCrossAxisExtent,Gridview会根据屏幕尺寸自动选择合适的行数量。
GridView.extent(
  maxCrossAxisExtent: 200,
  children: List.generate(
      8,
      (index) => Container(
            color: Colors.red[index % 8 * 100],
            child: Text("index $index"),
          )),
),
GridView.count()和GridView.extent()`可以看作GridView的语法糖。
使用PageView可以实现整屏页面滚动,默认为水平方向翻页。与ListView类似。
pageSnapping参数可以设置滑动时Page停留在任意位置。scrollDirection参数设置滚动方向(默认为水平方向)。PageView(
  pageSnapping: false, // 取消页面固定
  scrollDirection: Axis.vertical, // 设置为垂直方向滚动
  children: [
    for (int i = 0; i < 4; i++)
      Container(
        color: Colors.red[i % 4 * 100],
      )
  ],
),
使用PageView.builder()命名构造,可以动态加载页面。与ListView.builder()类似。
PageView.builder(
  pageSnapping: false,
  scrollDirection: Axis.vertical,
  itemBuilder: (BuildContext context, int index) => Container(
    color: Colors.red[index % 4 * 100],
  ),
),