目录
List里面常用的属性和方法:
Set
Map
forEach,map, where,any,every
extends抽象类 和 implements
Flutter环境搭建
入口文件、入口方法
第一个 Demo Center 组件的 使用
把内容单独抽离成一个组件
给 Text 组件增加一些装饰
用MaterialApp 和 Scaffold两个组件装饰 App
Text 组件
Container 组件
图片组件
引入本地图片
裁剪布局之 ClipRect、ClipRRect、ClipOval、ClipPath、CustomClipper
实现圆角以及实现圆形图片
圆形头像
ClipOval
② CircleAvatar
③ BoxDecoration BoxShape.circle
圆角头像
① ClipRRect
② BoxDecoration BoxShape.rectangle
列表组件概述
列表参数
基本列表
水平列表
动态列表(动态循环数据)
GridView 组件的常用参数
GridView.count 实现网格布局
GridView.builder 实现网格布局
Paddiing 组件
Row 水平布局组件
Column 垂直布局组件
Expanded 类似 Web 中的 Flex 布局
Stack 组件
Stack Align
Stack Positioned
AspectRatio 组件
Card 组件
Card 组件实现一个图文列表布局
RaisedButton 定义一个按钮
Wrap 组件
自定义有状态组件
BottomNavigationBar 组件
路由
基本路由使用
基本路由跳转传值
命名路由
命名路由跳转传值
命名路由单独抽离到一个文件
返回到上一级页面
替换路由
返回到根路由
AppBar 自定义顶部按钮图标、颜色
AppBar 中自定义 TabBar 实现顶部 Tab 切换
把 TabBar 放在导航最顶部
AppBar 中自定义 TabBar 实现 Tabs 的另一种方法。
Flutter Drawer 侧边栏
DrawerHeader
UserAccountsDrawerHeader
侧边栏路由跳转
按钮组件介绍
按钮组件中的一些属性
FloatingActionButton 介绍
常用表单介绍
TextField 文本框组件
Checkbox、CheckboxListTile 多选框组件
Radio、RadioListTile 单选按钮组件
开关 Switch
日期和时间戳
第三方库 date_format 的使用
调用自带日期组件和时间组件
调用自带日期组件和时间组件改为中文
调用第三方时间组件
轮播图组件
一、AlertDialog
二、SimpleDialog
三、showModalBottomSheet
四、showToast
自定义Dialog
定时器
定时器结合 Dialog
JSON 字符串和 Map 类型的转换(小项目)
使用 http 库进行网络请求
Dio 库
下拉刷新和上拉分页
下拉刷新
上拉分页加载更多
核心代码
完整代码
解决请求重复问题
滚动条回到顶部
参考代码
实现一个简单的新闻 APP
解析 html
WebView 组件 inappbrowser的使用
获取设备信息
使用高德定位准备工作获取 key
实现用高德定位
image_picker 实现相机拍照和相册选择
上传图片到服务器
视频播放
chewie 视频播放完整 demo
检测网络
检测网络完整 demo
本地存储
本地存储里面常用的一些方法
本地存储完整 demo
扫描二维码条形码插件
检测应用版本号、服务器下载文件以及实现 App 自动升级、安装
1、Android App 升级执行流程
2、升级 app 之前的准备工作配置权限
3、Android 升级 app 涉及的 API 库
4、获取版本信息
5、获取文件存储路径
6、下载文件
7、打开文件
8、注意事项
完整代码
调用 url_launcher 模块打开外部浏览器 打开外部应用 拨打电话 发送短信
Android 修改应用名称、应用图标、应用启动画面
**1**、Android 修改应用名称
**2**、Android 修改应用图标
**3**、Android 修改应用启动画面
竖向 ListView 嵌套横向 ListView ,以及ListView 嵌套 GridView
不同终端屏幕适配问题
JSON 序列化反序列化(模型类)
JSON字符串和Map类型的转换 dart:convert手动序列化 JSON
在模型类中序列化 JSON
json_to_dart 自动生成模型类
IndexedStack 保持页面状态
AutomaticKeepAliveClientMixin 保持页面状态
通过事件打开侧边栏
修改主题样式
下拉菜单 showMenu
弹出底部菜单
StatefulBuilder更新Flutter showDialog 、showModalBottomSheet 中的状态
状态管理
provider库和flutter provide库
provider 的使用
event_bus 事件广播 事件监听
MediaQuery.removePadding移除元素的pandding
瀑布流布局
Sliver牛逼!!!
适配夜间模式
夜间模式跟随系统
手动开启夜间模式
保存用户配置
状态管理
通用夜间模式Provider Model类
MaterialApp修改
登录注册案例
Flutter SliverAppBar 隐藏/显示导航栏
骨架屏
flutter 全屏背景图(包括appbar和状态栏)
极光推送:
指纹
List里面常用的属性和方法:
/* List里面常用的属性和方法: 常用属性: length 长度 reversed 翻转 isEmpty 是否为空 isNotEmpty 是否不为空 常用方法: add 增加 addAll 拼接数组 indexOf 查找 传入具体值 remove 删除 传入具体值 removeAt 删除 传入索引值 fillRange 修改 insert(index,value); 指定位置插入 insertAll(index,list) 指定位置插入List toList() 其他类型转换成List join() List转换成字符串 split() 字符串转化成List forEach map where any every */ void main(){ // List myList=['香蕉','苹果','西瓜']; // print(myList[1]); // var list=new List(); // list.add('111'); // list.add('222'); // print(list); //List里面的属性: // List myList=['香蕉','苹果','西瓜']; // print(myList.length); // print(myList.isEmpty); // print(myList.isNotEmpty); // print(myList.reversed); //对列表倒序排序 // var newMyList=myList.reversed.toList(); // print(newMyList); //List里面的方法: // List myList=['香蕉','苹果','西瓜']; //myList.add('桃子'); //增加数据 增加一个 // myList.addAll(['桃子','葡萄']); //拼接数组 // print(myList); //print(myList.indexOf('苹x果')); //indexOf查找数据 查找不到返回-1 查找到返回索引值 // myList.remove('西瓜'); // myList.removeAt(1); // print(myList); // List myList=['香蕉','苹果','西瓜']; // myList.fillRange(1, 2,'aaa'); //修改 // myList.fillRange(1, 3,'aaa'); // myList.insert(1,'aaa'); //插入 一个 // myList.insertAll(1, ['aaa','bbb']); //插入 多个 // print(myList); // List myList=['香蕉','苹果','西瓜']; // var str=myList.join('-'); //list转换成字符串 // print(str); // print(str is String); //true var str='香蕉-苹果-西瓜'; var list=str.split('-'); print(list); print(list is List); }
Set
//Set //用它最主要的功能就是去除数组重复内容 //Set是没有顺序且不能重复的集合,所以不能通过索引去获取值 void main(){ // var s=new Set(); // s.add('香蕉'); // s.add('苹果'); // s.add('苹果'); // print(s); //{香蕉, 苹果} // print(s.toList()); List myList=['香蕉','苹果','西瓜','香蕉','苹果','香蕉','苹果']; var s=new Set(); s.addAll(myList); print(s); print(s.toList()); }
Map
/* 映射(Maps)是无序的键值对: 常用属性: keys 获取所有的key值 values 获取所有的value值 isEmpty 是否为空 isNotEmpty 是否不为空 常用方法: remove(key) 删除指定key的数据 addAll({...}) 合并映射 给映射内增加属性 containsValue 查看映射内的值 返回true/false forEach map where any every */ void main(){ // Map person={ // "name":"张三", // "age":20 // }; // var m=new Map(); // m["name"]="李四"; // print(person); // print(m); //常用属性: // Map person={ // "name":"张三", // "age":20, // "sex":"男" // }; // print(person.keys.toList()); // print(person.values.toList()); // print(person.isEmpty); // print(person.isNotEmpty); //常用方法: Map person={ "name":"张三", "age":20, "sex":"男" }; // person.addAll({ // "work":['敲代码','送外卖'], // "height":160 // }); // print(person); // person.remove("sex"); // print(person); print(person.containsValue('张三')); }
forEach,map, where,any,every
/* forEach map where any every */ void main(){ // List myList=['香蕉','苹果','西瓜']; // for(var i=0;i<myList.length;i++){ // print(myList[i]); // } // for(var item in myList){ // print(item); // } // myList.forEach((value){ // print("$value"); // }); // List myList=[1,3,4]; // List newList=new List(); // for(var i=0;i<myList.length;i++){ // newList.add(myList[i]*2); // } // print(newList); // List myList=[1,3,4]; // var newList=myList.map((value){ // return value*2; // }); // print(newList.toList()); // List myList=[1,3,4,5,7,8,9]; // var newList=myList.where((value){ // return value>5; // }); // print(newList.toList()); // List myList=[1,3,4,5,7,8,9]; // var f=myList.any((value){ //只要集合里面有满足条件的就返回true // return value>5; // }); // print(f); // List myList=[1,3,4,5,7,8,9]; // var f=myList.every((value){ //每一个都满足条件返回true 否则返回false // return value>5; // }); // print(f); // set // var s=new Set(); // s.addAll([1,222,333]); // s.forEach((value)=>print(value)); //map Map person={ "name":"张三", "age":20 }; person.forEach((key,value){ print("$key---$value"); }); }
extends抽象类 和 implements
/* Dart中抽象类: Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。 1、抽象类通过abstract 关键字来定义 2、Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。 3、如果子类继承抽象类必须得实现里面的抽象方法 4、如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。 5、抽象类不能被实例化,只有继承它的子类可以 extends抽象类 和 implements的区别: 1、如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类 2、如果只是把抽象类当做标准的话我们就用implements实现抽象类 */
Flutter环境搭建
安装最新的 Xcode
下载androidstudio
https://developer.android.google.cn/studio
下载 Flutter SDK
https://flutter.dev/docs/development/tools/sdk/releases?tab=macos
把下载好的 Flutter SDK 随便减压到你想安装 Sdk 的目录如
/Users/cc/flutter
把 Flutter 安装目录的 bin 目录配置到环境变量,然后把 Flutter 国内镜像也配置到环境 变量里面
vim ~/.zshrc
export PATH=/Users/cc/flutter/bin:$PATH export ANDROID_HOME="/Users/cc/Library/Android/sdk" export PATH=${PATH}:${ANDROID_HOME}/tools export PATH=${PATH}:${ANDROID_HOME}/platform-tools export PUB_HOSTED_URL=https://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
source ~/.zshrc
flutter -h 如果能出来一些命令说明 flutter sdk 配置成功。
注意如果配置完成后输入 flutter -h 告诉你 flutter 不是内置命令之类的错误的话,可能 sdk 没有配置成功,也可能 sdk 下载的时候没有下载全
运行 flutter doctor 命令检测环境
入口文件、入口方法
每一个 flutter 项目的 lib 目录里面都有一个 main.dart 这个文件就是 flutter 的入口文件
main.dart 里面的
void main() { runApp(MyApp()); } //也可以简写 void main() => runApp(MyApp());
其中的 main 方法是 dart 的入口方法。runApp 方法是 flutter 的入口方法。 MyApp 是自定义的一个组件
第一个 Demo Center 组件的 使用
import 'package:flutter/material.dart'; void main() { runApp(Center( child: Text( "我是一个文本内容", textDirection: TextDirection.ltr, ), )); }
把内容单独抽离成一个组件
在 Flutter 中自定义组件其实就是一个类,这个类需要继承 StatelessWidget/StatefulWidget
前期我们都继承 StatelessWidget。后期给大家讲 StatefulWidget 的使用。
StatelessWidget 是无状态组件,状态不可变的 widget
StatefulWidget 是有状态组件,持有的状态可能在 widget 生命周期改变
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Text( "我是一个文本内容", textDirection: TextDirection.ltr, ), ); } }
给 Text 组件增加一些装饰
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Text( "我是一个文本内容", textDirection: TextDirection.ltr, style: TextStyle( fontSize: 40.0, fontWeight: FontWeight.bold, // color: Colors.yellow color: Color.fromRGBO(255, 222, 222, 0.5) ), ), ); } }
用MaterialApp 和 Scaffold两个组件装饰 App
1、MaterialApp
MaterialApp 是一个方便的 Widget,它封装了应用程序实现 Material Design 所需要的 一些 Widget。一般作为顶层 widget 使用。
常用的属性:
home(主页)
title(标题)
color(颜色)
theme(主题)
routes(路由)
…
2、Scaffold
Scaffold 是 Material Design 布局结构的基本实现。此类提供了用于显示 drawer、snackbar 和底部 sheet 的 API。
Scaffold 有下面几个主要属性:
appBar - 显示在界面顶部的一个 AppBar。
body - 当前界面所显示的主要内容 Widget。
drawer - 抽屉菜单控件。
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: "我是一个标题", home: Scaffold( appBar: AppBar( title: Text("Hello Flutter"), elevation: 30.0, 设置标题阴影 不需要的话值设置成 0.0 ), body: HomeContent(), ), theme: ThemeData( //设置主题颜色 primarySwatch: Colors.yellow), ); } } class HomeContent extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Text( "我是一个文本内容", textDirection: TextDirection.ltr, style: TextStyle( fontSize: 40.0, fontWeight: FontWeight.bold, // color: Colors.yellow color: Color.fromRGBO(255, 222, 222, 0.5) ), ), ); } }
Text 组件下面是 TextStyle 的参数 :更多函数:https://docs.flutter.io/flutter/painting/TextStyle-class.html
Container 组件更多参数:https://api.flutter.dev/flutter/widgets/Container-class.html
图片组件
图片组件是显示图像的组件,Image 组件有很多构造函数,这里我们只给大家讲两个
Image.asset 本地图片
Image.network 远程图片
Image 组件的常用属性:
更多属性参考:https://api.flutter.dev/flutter/widgets/Image-class.html
return Center( child: Container( child: Image.network( "http://pic.baike.soso.com/p/20130828/20130828161137-1346445960.jpg", alignment: Alignment.topLeft, color: Colors.red, colorBlendMode: BlendMode.colorDodge, // repeat: ImageRepeat.repeatX, fit: BoxFit.cover, ), width: 300.0, height: 400.0, decoration: BoxDecoration( color: Colors.yellow ), ), );
引入本地图片
emmm…不记了
裁剪布局之 ClipRect、ClipRRect、ClipOval、ClipPath、CustomClipper
widget 作用
ClipRect 将 child 剪裁为给定的矩形大小
ClipRRect 将 child 剪裁为圆角矩形
ClipOval 如果 child 为正方形时剪裁之后是圆形,如果 child 为矩形时,剪裁之后为椭圆形
ClipPath 将 child 按照给定的路径进行裁剪
CustomClipper 并不是一个widget,但是使用CustomClipper可以绘制出任何我们想要的形状
实现圆角以及实现圆形图片
实现圆角图片
return Center( child: Container( width: 300.0, height: 300.0, decoration: BoxDecoration( color: Colors.yellow, borderRadius: BorderRadius.circular(150), image: DecorationImage( image: NetworkImage( "http://pic.baike.soso.com/p/20130828/20130828161137-1346445960.jpg", ), fit: BoxFit.cover ) ), ), );
实现圆形图片
return Center( child: Container( child: ClipOval( child: Image.network( "https://www.itying.com/images/201905/thumb_img/1101_thumb_G_1557845381862.jpg", width: 150.0, height: 150.0, ), ), ), );
圆形头像
ClipOval
new ClipOval( child: new Image.asset(Utils.getImgPath('ali_connors')), )
② CircleAvatar
new CircleAvatar( radius: 36.0, backgroundImage: AssetImage( Utils.getImgPath('ali_connors'), ), )
③ BoxDecoration BoxShape.circle
new Container( width: 72.0, height: 72.0, decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( image: AssetImage( Utils.getImgPath('ali_connors'), ), ), ), )
圆角头像
① ClipRRect
new ClipRRect( borderRadius: BorderRadius.circular(6.0), child: new Image.asset(Utils.getImgPath('ali_connors')), )
② BoxDecoration BoxShape.rectangle
new Container( width: 88.0, height: 88.0, decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(6.0), image: DecorationImage( image: AssetImage( Utils.getImgPath('ali_connors'), ), ), ),
列表组件概述
列表布局是我们项目开发中最常用的一种布局方式。Flutter 中我们可以通过 ListView 来定义 列表项,支持垂直和水平方向展示。通过一个属性就可以控制列表的显示方向。列表有一下 分类:
**1、垂直列表(宽度自动扩展,设置宽度无效)**可以在外层包Container控制
2、垂直图文列表
**3、水平列表(高度自动扩展,设置高度无效)**可以在外层包Container控制
4、动态列表
5、矩阵式列表(网格布局)
列表参数
基本列表
class HomeContent extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: ListView( children: <Widget>[ ListTile( leading: Icon(Icons.phone), title: Text("this is list", style: TextStyle(fontSize: 28.0)), subtitle: Text('this is list this is list'), ), ListTile( title: Text("this is list"), subtitle: Text('this is list this is list'), trailing: Icon(Icons.phone), ), ListTile( title: Text("this is list"), subtitle: Text('this is list this is list'), ), ListTile( title: Text("this is list"), subtitle: Text('this is list this is list'), ), ListTile( title: Text("this is list"), subtitle: Text('this is list this is list'), ) ], ), ); } }
水平列表
class HomeContent extends StatelessWidget { @override Widget build(BuildContext context) { return Container( height: 200.0, margin: EdgeInsets.all(5), child: ListView( scrollDirection: Axis.horizontal, children: <Widget>[ Container( width: 180.0, color: Colors.lightBlue, ), Container( width: 180, color: Colors.amber, child: ListView( children: <Widget>[ Image.network( "https://resources.ninghao.org/images/childhood-in-a-picture.jpg"), SizedBox(height: 16.0), Text("这是一个文本信息", textAlign: TextAlign.center, style: TextStyle(fontSize: 16.0)), ], ), ) ], ), ); } }
动态列表(动态循环数据)
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("Hello Flutter")), body: HomeContent(), ), ); } } class HomeContent extends StatelessWidget { List list = List(); HomeContent() { for (int i = 0; i < 20; i++) { list.add("这是第$i条数据"); } print(list); } @override Widget build(BuildContext context) { return ListView.builder( itemCount: this.list.length, itemBuilder: (context, index) { // print(context); return ListTile( leading: Icon(Icons.phone), title: Text("${list[index]}"), ); }); } }
GridView 组件的常用参数
当数据量很大的时候用矩阵方式排列比较清晰。此时我们可以用网格列表组件 GridView 实现布局。
GridView 创建网格列表有多种方式,下面我们主要介绍两种。
1、可以通过 GridView.count 实现网格布局
2、通过 GridView.builder 实现网格布局
常用属性:
GridView.count 实现网格布局
import 'package:cc/res/listData.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("Hello Flutter")), body: LayoutContent(), ), ); } } class LayoutContent extends StatelessWidget { List<Widget> _getListData() { var tempList = listData.map((value) { return Container( child: Column( children: <Widget>[ Image.network(value["imageUrl"]), SizedBox(height: 12), Text(value["title"], textAlign: TextAlign.center, style: TextStyle(fontSize: 20)) ], ), decoration: BoxDecoration( border: Border.all( color: Color.fromRGBO(230, 230, 230, 0.9), width: 1.0)), ); }); // ('124124','124214') return tempList.toList(); } @override Widget build(BuildContext context) { return GridView.count( crossAxisCount: 2, crossAxisSpacing: 20, mainAxisSpacing: 20, // childAspectRatio:0.7, children: this._getListData(), ); } }
GridView.builder 实现网格布局
import 'package:cc/res/listData.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("Hello Flutter")), body: LayoutContent(), ), ); } } class LayoutContent extends StatelessWidget { Widget _getListData(context, index) { return Container( child: Column( children: <Widget>[ Image.network(listData[index]["imageUrl"]), SizedBox(height: 12), Text(listData[index]["title"], textAlign: TextAlign.center, style: TextStyle(fontSize: 20)) ], ), decoration: BoxDecoration( border: Border.all( color: Color.fromRGBO(230, 230, 230, 0.9), width: 1.0)), ); } @override Widget build(BuildContext context) { return GridView.builder( itemCount: listData.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( //横轴元素个数 crossAxisCount: 2, //纵轴间距 mainAxisSpacing: 20.0, //横轴间距 crossAxisSpacing: 10.0, //子组件宽高长度比例 childAspectRatio: 1.0), itemBuilder: this._getListData, ); } }
Paddiing 组件
在 html 中常见的布局标签都有 padding 属性,但是 Flutter 中很多 Widget 是没有 padding 属性。这个时候我们可以用 Padding 组件处理容器与子元素直接的间距。
class LayoutDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.fromLTRB(0, 0, 10, 0), child: GridView.count( crossAxisCount: 2, childAspectRatio: 1.5, children: <Widget>[ Padding( padding: EdgeInsets.fromLTRB(10, 10, 0, 0), child: Image.network("https://www.itying.com/images/flutter/1.png", fit: BoxFit.cover), ), Padding( padding: EdgeInsets.fromLTRB(10, 10, 0, 0), child: Image.network("https://www.itying.com/images/flutter/2.png", fit: BoxFit.cover), ), Padding( padding: EdgeInsets.fromLTRB(10, 10, 0, 0), child: Image.network("https://www.itying.com/images/flutter/3.png", fit: BoxFit.cover), ), Padding( padding: EdgeInsets.fromLTRB(10, 10, 0, 0), child: Image.network("https://www.itying.com/images/flutter/4.png", fit: BoxFit.cover), ), Padding( padding: EdgeInsets.fromLTRB(10, 10, 0, 0), child: Image.network("https://www.itying.com/images/flutter/5.png", fit: BoxFit.cover), ), Padding( padding: EdgeInsets.fromLTRB(10, 10, 0, 0), child: Image.network("https://www.itying.com/images/flutter/6.png", fit: BoxFit.cover), ), ], ), ); } }
Row 水平布局组件
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("Hello Flutter")), body: LayoutDemo(), ), ); } } class LayoutDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( height: 700, width: 500, color: Colors.black26, child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, // crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ IconContainer(Icons.home, color: Colors.red), IconContainer(Icons.home, color: Colors.blue), IconContainer(Icons.home, color: Colors.orange), ], ), ); } } class IconContainer extends StatelessWidget { double size; IconData icon; Color color; IconContainer(this.icon, {this.size, this.color = Colors.blue}) { this.size = 32.0; } @override Widget build(BuildContext context) { return Container( width: this.size + 60, height: this.size + 60, color: this.color, child: Center( child: Icon( this.icon, color: Colors.white, size: this.size, )), ); } }
Column 垂直布局组件
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("Hello Flutter")), body: LayoutDemo(), ), ); } } class LayoutDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Container( height: 700, width: 500, color: Colors.black26, child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, // crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ IconContainer(Icons.home, color: Colors.red), IconContainer(Icons.home, color: Colors.blue), IconContainer(Icons.home, color: Colors.orange), ], ), ); } } class IconContainer extends StatelessWidget { double size; IconData icon; Color color; IconContainer(this.icon, {this.size, this.color = Colors.blue}) { this.size = 32.0; } @override Widget build(BuildContext context) { return Container( width: this.size + 60, height: this.size + 60, color: this.color, child: Center( child: Icon( this.icon, color: Colors.white, size: this.size, )), ); } }
Expanded 类似 Web 中的 Flex 布局
Expanded 可以用在 Row 和 Column 布局中
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("Hello Flutter")), body: LayoutDemo(), ), ); } } class LayoutDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.all(10), child: Row( // crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, // crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Expanded(flex: 2, child: IconContainer(Icons.home)), SizedBox(width: 10), Expanded(flex: 3, child: IconContainer(Icons.search)), // SizedBox(width: 10), // Expanded(child: IconContainer(Icons.send)) ], ), ); } } class IconContainer extends StatelessWidget { double size; IconData icon; IconContainer(this.icon, {this.size}) { this.size = 32.0; } @override Widget build(BuildContext context) { return Container( width: 100.0, height: 100.0, color: Colors.blue, child: Center(child: Icon(this.icon, color: Colors.white, size: this.size)), ); } }