【Flutter】flutter初学习笔记

【Flutter】flutter初学习笔记

Flutter 是Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。 开发者可以通过Dart语言开发App,一套代码同时运行在iOS 和Android平台。 Flutter提供了丰富的组件、接口,开发者可以很快地为Flutter添加native扩展。

以下是个人学习笔记

Text Widget

TextAlign属性:left(左对齐)、center(居中对齐)、right(右对齐)

maxLines属性:设置最多显示的行数

overflow属性:clip:直剩下的文字不显示;ellipsis:显示省略号;

fade:溢出的部分会进行一个上线的渐变消失的效果

style属性:见https://docs.flutter.io/flutter/painting/TextStyle-class.html

Container(容器控件)

Alignment属性

1
2
3
4
5
6
7
8
9
bottomCenter:下部居中对齐。
botomLeft: 下部左对齐。
bottomRight:下部右对齐。
center:纵横双向居中对齐。
centerLeft:纵向居中横向居左对齐。
centerRight:纵向居中横向居右对齐。
topLeft:顶部左侧对齐。
topCenter:顶部居中对齐。
topRight: 顶部居左对齐。

设置宽、高和颜色属性

1
2
3
width:500.0,
height:400.0,
color: Colors.lightBlue,

padding属性

margin属性

decoration属性: container 的修饰器,设置背景和边框

1
2
3
4
5
6
decoration:new BoxDecoration( // 渐变
gradient:const LinearGradient(
colors:[Colors.lightBlue,Colors.greenAccent,Colors.purple] // 颜色
),
border:Border.all(width:2.0,color:Colors.red) // 边框
),

Image图片组件

路径属性

1
2
3
4
Image.asset:加载资源图片,相对路径。
Image.network:网络资源图片。
Image.file:加载本地图片,绝对路径。
Image.memory: 加载Uint8List资源图片。

fit属性的设置:控制图片的拉伸和挤压

1
2
3
4
5
6
BoxFit.fill:全图显示,图片会被拉伸,并充满父容器。
BoxFit.contain:全图显示,显示原比例,可能会有空隙。
BoxFit.cover:显示可能拉伸,可能裁切,充满(图片要充满整个容器,还不变形)。
BoxFit.fitWidth:宽度充满(横向充满),显示可能拉伸,可能裁切。
BoxFit.fitHeight :高度充满(竖向充满),显示可能拉伸,可能裁切。
BoxFit.scaleDown:效果和contain差不多,但是此属性不允许显示超过源图片大小,可小不可大

colorBlendMode(图片混合模式)

1
2
color:是要混合的颜色,如果你只设置color是没有意义的。
colorBlendMode:是混合模式,相当于我们如何混合。

repeat图片重复

1
2
3
ImageRepeat.repeat : 横向和纵向都进行重复,直到铺满整个画布。
ImageRepeat.repeatX: 横向重复,纵向不重复。
ImageRepeat.repeatY:纵向重复,横向不重复。

ListView 列表组件

demo

1
2
3
4
5
6
7
8
body: new ListView(
children:<Widget>[
new ListTile(
leading: new Icon(Icons.access_time),
title: new Text('access_time')
)
]
),

图片列表的使用:将ListTile替换成Image Widget

横向列表的使用

ListView组件里加一个ScrollDirection属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Axis.horizontal:横向滚动或者叫水平方向滚动。
Axis.vertical:纵向滚动或者叫垂直方向滚动。
child:new ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
new Container(
width:180.0,
color: Colors.lightBlue,
),
new Container(
width:180.0,
color: Colors.amber,
),
new Container(
width:180.0,
color: Colors.deepOrange,
),
],
)

动态列表的使用

List类型的使用:

1
2
3
4
5
var myList = List(): 非固定长度的声明。
var myList = List(2): 固定长度的声明。
var myList= List<String>():固定类型的声明方式。
var myList = [1,2,3]: 对List直接赋值。
动态列表 ListView.builder()

GridView网格列表组件

padding:表示内边距,这个小伙伴们应该很熟悉。

crossAxisSpacing:网格间的空当,相当于每个网格之间的间距。

crossAxisCount:网格的列数,相当于一行放置的网格数量。

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
body:GridView.count(
padding:const EdgeInsets.all(20.0),
crossAxisSpacing: 10.0,
crossAxisCount: 3,
children: <Widget>[
const Text('I am Jspang'),
const Text('I love Web'),
const Text('jspang.com'),
const Text('我喜欢玩游戏'),
const Text('我喜欢看书'),
const Text('我喜欢吃火锅')
],
)

水平布局Row的使用

自适应:Expanded

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
body:new Row(
children: <Widget>[
Expanded(
child:new RaisedButton(
onPressed: (){
},
color:Colors.redAccent,
child:new Text('红色按钮')
)
),
Expanded(child:new RaisedButton(
onPressed: (){
},
color:Colors.orangeAccent,
child: new Text('黄色按钮'),
)
),
Expanded(child:new RaisedButton(
onPressed: (){
},
color:Colors.pinkAccent,
child:new Text('粉色按钮')
)
)
],
)

非自适应

1
2
3
4
5
6
7
8
body:new Row(
children: <Widget>[
new RaisedButton(
onPressed: (){
},
color:Colors.redAccent,
child:new Text('红色按钮')
),

垂直布局Column组件

1
2
3
4
5
6
7
body:Column(
children: <Widget>[
Text('I am JSPang'),
Text('my website is jspang.com'),
Text('I love coding')
],
)
1
2
3
4
5
6
CrossAxisAlignment.star:居左对齐。
CrossAxisAlignment.end:居右对齐。
CrossAxisAlignment.center:居中对齐。

main轴:如果你用column组件,那垂直就是主轴,如果你用Row组件,那水平就是主轴。
cross轴:cross轴我们称为幅轴,是和主轴垂直的方向。比如Row组件,那垂直就是幅轴,Column组件的幅轴就是水平方向的。
1
2
3
4
5
6
7
8
9
body:Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('I am JSPang'),
Text('my website is jspang.com'),
Text('I love coding')
],
)

水平方向相对屏幕居中

1
2
3
4
5
6
7
8
body:Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(child:Text('I am JSPang')),
Center(child:Text('my website is jspang.com')),
Center(child:Text('I love coding'))
],
)

Expanded属性的使用

1
2
3
4
5
6
7
8
body:Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(child:Text('I am JSPang')),
Expanded(child:Center(child:Text('my website is jspang.com'))),
Center(child:Text('I love coding'))
],
)

Stack层叠布局

层叠布局的 alignment 属性:alignment属性是控制层叠的位置的,建议在两个内容进行层叠时使用。它有两个值X轴距离和Y轴距离,值是从0到1的,都是从上层容器的左上角开始算起的

CircleAvatar组件的使用,常用于头像之类的

1
2
3
4
new CircleAvatar(
backgroundImage: new NetworkImage(''),
radius: 100.0,
),

Positioned组件

1
2
3
4
5
6
bottom: 距离层叠组件下边的距离
left:距离层叠组件左边的距离
top:距离层叠组件上边的距离
right:距离层叠组件右边的距离
width: 层叠定位组件的宽度
height: 层叠定位组件的高度

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var stack = new Stack(
children: <Widget>[
new CircleAvatar(
backgroundImage: new NetworkImage('http://jspang.com/static//myimg/blogtouxiang.jpg'),
radius: 100.0,
),
new Positioned(
top:10.0,
left:10.0,
child: new Text('JSPang.com'),
),
new Positioned(
bottom:10.0,
right:10.0,
child: new Text('技术胖'),
)
],
);

卡片组件布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var card = new Card(
child: Column(
children: <Widget>[
ListTile(
title:new Text('吉林省吉林市昌邑区',style: TextStyle(fontWeight: FontWeight.w500),),
subtitle: new Text('技术胖:1513938888'),
leading: new Icon(Icons.account_box,color: Colors.lightBlue,),
),
new Divider(),
ListTile(
title:new Text('北京市海淀区中国科技大学',style: TextStyle(fontWeight: FontWeight.w500),),
subtitle: new Text('胜宏宇:1513938888'),
leading: new Icon(Icons.account_box,color: Colors.lightBlue,),
),
new Dvider(),

],
),
)

route路由层级

1
2
3
4
5
6
7
RaisedButton按钮组件
child:可以放入容器,图标,文字。让你构建多彩的按钮。
onPressed:点击事件的相应,一般会调用Navigator组件。

Navigator.push 和 Navigator.pop
Navigator.push:是跳转到下一个页面,它要接受两个参数一个是上下文context,另一个是要跳转的函数。
Navigator.pop:是返回到上一个页面,使用时传递一个context(上下文)参数,使用时要注意的是,你必须是有上级页面的,也就是说上级页面使用了Navigator.push。

导航参数的传递和接收

声明数据结构类:

Dart中可以使用类来抽象一个数据,比如我们模仿一个商品信息,有商品标题和商品描述。我们定义了一个Product类,里边有两个字符型变量,title和description。

title:是商品标题。

description: 商品详情描述

代码如下:

1
2
3
4
5
class Product{
final String title; //商品标题
final String description; //商品描述
Product(this.title,this.description);
}

构建一个商品列表

1
2
3
4
5
6
7
8
9
10
11
void main(){
runApp(MaterialApp(
title:'数据传递案例',
home:ProductList(
products:List.generate(
20,
(i)=>Product('商品 $i','这是一个商品详情,编号为:$i')
),
)
));
}

导航参数的传递:使用Navigator组件,然后使用路由MaterialPageRoute传递参数

1
2
3
4
5
6
Navigator.push(
context,
MaterialPageRoute(
builder:(context)=>new ProductDetail(product:products[index])
)
);

子页面接受参数并显示,需要声明ProductDetail这个类(组件),先要作的就是接受参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import 'package:flutter/material.dart';
//传递的数据结构,也可以理解为对商品数据的抽象
class Product{
final String title; //商品标题
final String description; //商品描述
Product(this.title,this.description);
}
void main(){
runApp(MaterialApp(
title:'数据传递案例',
home:ProductList(
products:List.generate(
20,
(i)=>Product('商品 $i','这是一个商品详情,编号为:$i')
),
)
));
}
class ProductList extends StatelessWidget{
final List<Product> products;
ProductList({Key key,@required this.products}):super(key:key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('商品列表')),
body:ListView.builder(
itemCount:products.length,
itemBuilder: (context,index){
return ListTile(
title:Text(products[index].title),
onTap:(){
Navigator.push(
context,
MaterialPageRoute(
builder:(context)=>new ProductDetail(product:products[index])
)
);
}
);
},
)
);
}
}
class ProductDetail extends StatelessWidget {
final Product product;
ProductDetail({Key key ,@required this.product}):super(key:key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title:Text('${product.title}'),
),
body:Center(child: Text('${product.description}'),)
);
}
}

页面跳转并返回数据

异步请求和等待:async…await

1
2
3
SnackBar的使用
SnackBar是用户操作后,显示提示信息的一个控件,类似Tost,会自动隐藏。SnackBar是以Scaffold的showSnackBar方法来进行显示的。
Scaffold.of(context).showSnackBar(SnackBar(content:Text('$result')));

返回数据的方式

返回数据其实是特别容易的,只要在返回时带第二个参数就可以了。

Navigator.pop(context,’xxxx’); //xxx就是返回的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import 'package:flutter/material.dart';
void main(){
runApp(MaterialApp(
title:'页面跳转返回数据',
home:FirstPage()
));
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(title:Text("找小姐姐要电话")),
body:Center(
child: RouteButton(),
)
);
}
}
//跳转的Button
class RouteButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed:(){
_navigateToXiaoJieJie(context);
},
child: Text('去找小姐姐'),
);
}
_navigateToXiaoJieJie(BuildContext context) async{ //async是启用异步方法
final result = await Navigator.push(//等待
context,
MaterialPageRoute(builder: (context)=> XiaoJieJie())
);
Scaffold.of(context).showSnackBar(SnackBar(content:Text('$result')));
}
}
class XiaoJieJie extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text('我是小姐姐')
),
body:Center(
child:Column(
children: <Widget>[
RaisedButton(
child: Text('大长腿小姐姐'),
onPressed: (){
Navigator.pop(context,'大长腿:1511008888');
},
) ,
RaisedButton(
child: Text('小蛮腰小姐姐'),
onPressed: (){
Navigator.pop(context,'大长腿:1511009999');
},
) ,
],
)
) ,
);
}
}

静态资源和项目图片的处理

pubspec.yaml

如果想配置项目资源文件,就需要使用pubspec.yaml文件,需要把资源文件在这里声明。

比如在项目根目录下新建了一个images文件夹,文件夹下面放了一个图片,图片的名称叫做blogtouxiang.jpg,那我们在pubspec.yaml文件里就要写如下代码进行声明。

1
2
assets:
- images/blogtouxiang.jpg

使用项目图片资源

有了声明后,我们就可以直接在项目中引用这个文件了。这里使用最简单的代码结构,只用了一张图片。代码如下:

1
2
3
4
5
6
7
8
9
10
import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Image.asset('images/blogtouxiang.jpg'),
);
}
}

Flutter客户端打包

配置

项目根目录/android/app/src/main/res/AndroidManifest.xml文件
这个文件主要用来配置APP的名称、图标和系统权限,所在的目录在:

1
2
3
项目根目录/android/app/src/main/AndroidManifest.xml
android:label="flutter_app" //配置APP的名称,支持中文
android:icon="@mipmap/ic_launcher" //APP图标的文件名称

生成 keystore

D:\Program\Android\'Android Studio'\jre\bin\keytool -genkey -v -keystore D:\key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

有了这个key.jks文件后,可以到项目目录下的android文件夹下,创建一个名为key.properties的文件,并打开粘贴下面的代码。

1
2
3
4
storePassword=<password from previous step>    //输入上一步创建KEY时输入的 密钥库 密码
keyPassword=<password from previous step> //输入上一步创建KEY时输入的 密钥 密码
keyAlias=key
storeFile=<E:/key.jks> //key.jks的存放路径

配置key注册

key生成好后,需要在build.gradle文件中进行配置。这个过程其实很简单,就是粘贴复制一些东西,你是不需要知道这些文件的具体用处的。

第一项:

进入项目目录的/android/app/build.gradle文件,在android{这一行前面,加入如下代码:

1
2
3
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

把如下代码进行替换

1
2
3
4
5
buildTypes {
release {
signingConfig signingConfigs.debug
}
}

替换成的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}

生成apk

flutter build apk

【Flutter】flutter初学习笔记

https://blog.vadxq.com/article/flutter-study-notes/

作者

vadxq

发布于

2019-02-08

更新于

2019-02-15

许可协议

评论