Flutter基础笔记
Posted Lucklyの博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter基础笔记相关的知识,希望对你有一定的参考价值。
目录
- List里面常用的属性和方法:
- Set
- Map
- forEach,map, where,any,every
- extends抽象类 和 implements
- Flutter环境搭建
- 入口文件、入口方法
- 第一个 Demo Center 组件的 使用
- 把内容单独抽离成一个组件
- 给 Text 组件增加一些装饰
- 用MaterialApp 和 Scaffold两个组件装饰 App
- Text 组件
- Container 组件
- 图片组件
- 引入本地图片
- 裁剪布局之 ClipRect、ClipRRect、ClipOval、ClipPath、CustomClipper
- 实现圆角以及实现圆形图片
- 列表组件概述
- 列表参数
- 基本列表
- 水平列表
- 动态列表(动态循环数据)
- 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 自动升级、安装
- 调用 url_launcher 模块打开外部浏览器 打开外部应用 拨打电话 发送短信
- 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牛逼!!!
- 适配夜间模式
- 登录注册案例
- 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 组件
名称 | 功能 |
---|---|
textAlign | 文本对齐方式(center 居中,left 左 对齐,right 右对齐,justfy 两端对齐) |
textDirection | 文本方向(ltr 从左至右,rtl 从右至 左) |
overflow | 文字超出屏幕之后的处理方式(clip 裁剪,fade 渐隐,ellipsis 省略号) |
textScaleFactor | 字体显示倍率 |
maxLines | 文字显示最大行数 |
style | 字体的样式设置 |
下面是 TextStyle 的参数 :
名称 | 功能 |
---|---|
decoration | 文字装饰线(none 没有线,lineThrough 删 除线,overline 上划线,underline 下划线) |
decorationColor | 文字装饰线颜色 |
decorationStyle | 文字装饰线风格([dashed,dotted]虚线, double 两根线,solid 一根实线,wavy 波浪 线) |
wordSpacing | 单词间隙(如果是负值,会让单词变得更紧 凑 |
letterSpacing | 字母间隙(如果是负值,会让字母变得更紧 凑) |
fontStyle | 文字样式(italic 斜体,normal 正常体) |
fontSize | 文字大小 |
color | 文字颜色 |
fontWeight | 字体粗细(bold 粗体,normal 正常体) |
更多参数:https://docs.flutter.io/flutter/painting/TextStyle-class.html
Container 组件
名称 | 功能 |
---|---|
alignment | topCenter:顶部居中对齐 topLeft:顶部左对齐 topRight:顶部右对齐 center:水平垂直居中对齐 centerLeft:垂直居中水平居左对齐 centerRight:垂直居中水平居右对齐 bottomCenter 底部居中对齐 bottomLeft:底部居左对齐 bottomRight:底部居右对齐 |
decoration | decoration: BoxDecoration( color: Colors.blue, border: Border.all( color: Colors.red, width: 2.0, ), borderRadius: BorderRadius.all( Radius.circular(8.0) ) ) |
margin | margin 属性是表示 Container 与外部其他 组件的距离。 EdgeInsets.all(20.0), |
padding | padding 就是 Container 的内边距,指 Container 边缘与 Child 之间的距离 padding: EdgeInsets.all(10.0) |
transform | 让 Container 容易进行一些旋转之类的 transform: Matrix4.rotationZ(0.2) |
height | 容器高度 |
width | 容器宽度 |
child | 容器子元素 |
更多参数:https://api.flutter.dev/flutter/widgets/Container-class.html
图片组件
图片组件是显示图像的组件,Image 组件有很多构造函数,这里我们只给大家讲两个
Image.asset 本地图片
Image.network 远程图片
Image 组件的常用属性:
名称 | 类型 | 说明 |
---|---|---|
alignment | alignment | 图片的对齐方式 |
color 和 colorBlendMode | 设置图片的背景颜色,通常和 colorBlendMode 配合一起使用,这样可以是图片颜色和背景色混合。上面的图片就是进行了颜色的混合,绿色背景和图片红色的混合 | |
fit | BoxFit | fit 属性用来控制图片的拉伸和挤压,这都是根据父容器来的。 BoxFit.fill:全图显示,图片会被拉伸,并充满父容器。 BoxFit.contain:全图显示,显示原比例,可能会有空隙。 BoxFit.cover:显示可能拉伸,可能裁切,充满(图片要充满整个容器,还不变形)。 BoxFit.fitWidth:宽度充满(横向充满),显示可能拉伸,可能裁切。 BoxFit.fitHeight :高度充满(竖向充满),显示可能拉伸,可能裁切。 BoxFit.scaleDown:效果和 contain 差不多,但是此属性不允许显示超过源图片大小,可小不可大。 |
repeat | 平铺 | ImageRepeat.repeat : 横向和纵向都进行重复,直到铺满整个画布。 ImageRepeat.repeatX: 横向重复,纵向不重复。 ImageRepeat.repeatY:纵向重复,横向不重复。 |
width | 宽度 一般结合 ClipOval 才能看到效果 | |
height | 高度 一般结合 ClipOval 才能看到效果 |
更多属性参考: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、矩阵式列表(网格布局)
列表参数
名称 | 类型 | 说明 |
---|---|---|
scrollDirection | Axis | Axis.horizontal 水平列表 Axis.vertical 垂直列表 |
padding | EdgeInsetsGeometry | 内边距 |
resolve | bool | 组件反向排序 |
children | List | 列表元素 |
基本列表
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 实现网格布局
常用属性:
名称 | 类型 | 说明 |
---|---|---|
scrollDirection | Axis | 滚动方法 |
padding | EdgeInsetsGeometry | 内边距 |
resolve | bool | 组件反向排序 |
crossAxisSpacing | double | 水平子 Widget 之间间距 |
mainAxisSpacing | double | 垂直子 Widget 之间间距 |
crossAxisCount | int | 一行的 Widget 数量 |
childAspectRatio | double | 子 Widget 宽高比例 |
children | [ ] | |
gridDelegate | SliverGridDelegateWithFix edCrossAxisCount(常用) SliverGridDelegateWithMax CrossAxisExtent | 控制布局主要用在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 组件处理容器与子元素直接的间距。
属性 | 说明 |
---|---|
padding | padding 值, EdgeInsetss 设置填充的值 |
child | 子组件 |
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 水平布局组件
属性 | 说明 |
---|---|
mainAxisAlignment | 主轴的排序方式 |
crossAxisAlignment | 次轴的排序方式 |
children | 组件子元素 |
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 垂直布局组件
属性 | 说明 |
---|---|
mainAxisAlignment | 主轴的排序方式 |
crossAxisAlignment | 次轴的排序方式 |
children | 组件子元素 |
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 布局中
属性 | 说明 |
---|---|
flex | 元素站整个父 Row /Column 的比例 |
child | 子元素 |
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)),
);
}
}
Stack 组件
Stack 表示堆的意思,我们可以用 Stack 或者 Stack 结合 Align 或者 Stack 结合 Positiond 来实现页面的定位布局
属性 | 说明 |
---|---|
alignment | 配置所有子元素的显示位置 |
children | 子组件 |
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Stack(
alignment: Alignment.topLeft,
children: <Widget>[
Container(
height: 400,
width: 300,
color: Colors.red,
),
Text('我是一个文本',style: TextStyle(
fontSize: 40,
color: Colors.white
))
],
),
);
}
}
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Stack(
alignment: Alignment(1,0.3),
children: <Widget>[
Container(
height: 400,
width: 300,
color: Colors.red,
),
Text('我是一个文本',style: TextStyle(
fontSize: 20,
color: Colors.white
))
],
),
);
}
}
Stack Align
Stack 组件中结合 Align 组件可以控制每个子元素的显示位置
属性 | 说明 |
---|---|
alignment | 配置所有子元素的显示位置 |
child | 子组件 |
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
height: 400,
width: 300,
color: Colors.red,
child: Stack(
// alignment: Alignment.center,
children: <Widget>[
Align(
alignment: Alignment(1,-0.2),
child: Icon(Icons.home,size: 40,color: Colors.white),
),
Align(
alignment: Alignment.center,
child: Icon(Icons.search,size: 30,color: Colors.white),
),
Align(
alignment: Alignment.bottomRight,
child: Icon(Icons.settings_applications,size: 30,color: Colors.white),
)
],
),
),
);
}
}
Stack Positioned
Stack 组件中结合 Positioned 组件也可以控制每个子元素的显示位置
属性 | 说明 |
---|---|
top | 子元素距离顶部的距离 |
bottom | 子元素距离底部的距离 |
left | 子元素距离左侧距离 |
right | 子元素距离右侧距离 |
child | 子组件 |
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
height: 400,
width: 300,
color: Colors.red,
child: Stack(
// alignment: Alignment.center,
children: <Widget>[
Positioned(
// left: 10,
child: Icon(Icons.home,size: 40,color: Colors.white),
),
Positioned(
bottom: 0,
left: 100,
child: Icon(Icons.search,size: 30,color: Colors.white),
),
Positioned(
right: 0,
child: Icon(Icons.settings_applications,size: 30,color: Colors.white),
)
],
),
),
);
}
}
AspectRatio 组件
AspectRatio 的作用是根据设置调整子元素 child 的宽高比。
AspectRatio 首先会在布局限制条件允许的范围内尽可能的扩展,widget 的高度是由宽度和比率决定的,类似于 BoxFit 中的 contain,按照固定比率去尽量占满区域。
如果在满足所有限制条件过后无法找到一个可行的尺寸,AspectRatio 最终将会去优先适应布局限制条件,而忽略所设置的比率。
属性 | 说明 |
---|---|
aspectRatio | 宽高比,最终可能不会根据这个值去布局,具体则要看综合因素,外层是否允许按照这种比率进行布局,这只是一个参考值 |
child | 子组件 |
return Center(
child: Container(
width: 200,
child: AspectRatio(
aspectRatio: 2.0 / 1.0,
child: Container(
color: Colors.red,
),
),
),
);
Card 组件
Card 是卡片组件块,内容可以由大多数类型的 Widget 构成,Card 具有圆角和阴影,这让它看起来有立体感。
属性 | 说明 |
---|---|
margin | 外边距 |
child | 子组件 |
Shape | Card 的阴影效果,默认的阴影效果为圆角的长方形边。 |
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
ListTile(
title: Text(
"张三",
style: TextStyle(fontSize: 28),
),
subtitle: Text("高级软件工程师"),
),
Divider(),
ListTile(
title: Text("电话:123123123"),
),
ListTile(
title: Text("地址:北京市海淀区"),
)
],
),
),
Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
ListTile(
title: Text(
"李四",
style: TextStyle(fontSize: 28),
),
subtitle: Text("高级软件工程师"),
),
Divider(),
ListTile(
title: Text("电话:123123123"),
),
ListTile(
title: Text("地址:北京市海淀区"),
)
],
),
),
],
);
}
}
Card 组件实现一个图文列表布局
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: listData.map((value) {
return Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
AspectRatio(
aspectRatio: 16 / 9,
child: Image.network(value["imageUrl"], fit: BoxFit.cover),
),
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(value["imageUrl"]),
),
title: Text(value["description"]),
subtitle: Text(
value["description"],
overflow: TextOverflow.ellipsis,
),
)
],
),
);
}).toList());
}
}
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: listData.length,
itemBuilder: (context,index){
return Card(
margin: EdgeInsets.all(10),
child: Column(
children: <Widget>[
AspectRatio(
aspectRatio: 16 / 9,
child: Image.network(listData[index]["imageUrl"], fit: BoxFit.cover),
),
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(listData[index]["imageUrl"]),
),
title: Text(listData[index]["description"]),
subtitle: Text(
listData[index]["description"],
overflow: TextOverflow.ellipsis,
),
)
],
),
);
},
);
}
}
RaisedButton 定义一个按钮
Flutter 中通过 RaisedButton 定义一个按钮。RaisedButton 里面有很多的参数,这一讲我们只是简单的进行使用。
return RaisedButton(
child: Text("Flutter"),
textColor: Theme.of(context).accentColor,
onPressed: (){
});
Wrap 组件
Wrap 可以实现流布局,单行的 Wrap 跟 Row 表现几乎一致,单列的 Wrap 则跟 Row 表 现几乎一致。但 Row 与 Column 都是单行单列的,Wrap 则突破了这个限制,mainAxis 上空 间不足时,则向 crossAxis 上去扩展显示。
属性 | 说明 |
---|---|
direction | 主轴的方向,默认水平 |
alignment | 主轴的对其方式 |
spacing | 主轴方向上的间距 |
textDirection | 文本方向 |
verticalDirection | 定义了 children 摆放顺序,默认是 down,见Flex 相关属性介绍。 |
runAlignment | run 的对齐方式。run 可以理解为新的行或者列,如果是水平方向布局的话,run 可以理解为新的一行 |
runSpacing | run 的间距 |
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
Widge以上是关于Flutter基础笔记的主要内容,如果未能解决你的问题,请参考以下文章
在 webview_flutter 中启用捏合和缩放,在哪里添加代码片段 [this.webView.getSettings().setBuiltInZoomControls(true);]
Flutterflutter doctor 报错Android license status unknown. Run `flutter doctor --android-licenses‘(代码片段