flutter - 01 基础介绍以及ListView
这篇主要讲flutter最基本的操作。我们从一个实例入手,先不需要知道它里面的每一行是什么意思,我会慢慢说。
main.dart
1 import 'package:flutter/material.dart';
2 import 'model/post.dart';
3
4 void main() => runApp(App());
5
6
7 class App extends StatelessWidget {
8 @override
9 Widget build(BuildContext context) {
10 return MaterialApp(
11 home: Home(),
12 theme: ThemeData(
13 primarySwatch: Colors.red
14 ),
15 );
16 }
17 }
18
19 class Home extends StatelessWidget {
20 Widget _listItemBuilder (BuildContext context, int index) {
21 return Container(
22 color: Colors.white,
23 margin: EdgeInsets.all(8.0),
24 child: Column(
25 children: <Widget>[
26 Image.network(posts[index].imageUrl),
27 SizedBox(height: 16.0),
28 Text(
29 posts[index].title,
30 style: Theme.of(context).textTheme.title,
31 ),
32 Text(
33 posts[index].author,
34 style: Theme.of(context).textTheme.subhead,
35 ),
36 SizedBox(height: 8.0),
37 ],
38 ),
39 );
40 }
41
42 @override
43 Widget build(BuildContext context) {
44 // TODO: implement build
45 return Scaffold(
46 backgroundColor: Colors.grey[200],
47 appBar: AppBar(
48 title: Text('Hello'),
49 elevation: 4.0,
50 ),
51 body: ListView.builder(
52 itemCount: posts.length,
53 itemBuilder: _listItemBuilder,
54 ),
55 );
56 }
57 }
58
59 class Hello extends StatelessWidget {
60 @override
61 Widget build(BuildContext context) {
62 return Center(
63 child: Text(
64 'hello liwenchi',
65 textDirection: TextDirection.ltr,
66 style: TextStyle(
67 fontSize: 30,
68 color: Colors.blue
69 ),
70 )
71 );
72 }
73 }
View Code
第一行是指引入flutter自带的material风格的组件库。
第二行是指引入了一个自己定义的文件,同级目录下的model文件夹的post.dart,是自己创建的,里面有一些post,以便练习ViewList。
post.dart
1 import 'package:english_words/english_words.dart';
2
3 class Post {
4 const Post({
5 this.title,
6 this.author,
7 this.imageUrl
8 });
9
10 final title;
11 final author;
12 final imageUrl;
13 }
14
15 var wordPair = new WordPair.random();
16
17 final List<Post> posts = [
18 Post (
19 title: wordPair.asPascalCase,
20 author: wordPair.asPascalCase,
21 imageUrl: 'https://img1.gamersky.com/image2019/04/20190420_ljt_red_220_4/gamersky_020small_040_201942016592D9.jpg'
22 ),
23 Post (
24 title: wordPair.asPascalCase,
25 author: wordPair.asPascalCase,
26 imageUrl: 'https://img1.gamersky.com/image2019/04/20190420_ljt_red_220_4/gamersky_019origin_037_2019420165980D.jpg'
27 ),
28 Post (
29 title: wordPair.asPascalCase,
30 author: wordPair.asPascalCase,
31 imageUrl: 'https://img1.gamersky.com/image2019/04/20190420_ljt_red_220_4/gamersky_002small_004_201942016591DC.jpg'
32 ),
33 Post (
34 title: wordPair.asPascalCase,
35 author: wordPair.asPascalCase,
36 imageUrl: 'https://img1.gamersky.com/image2019/04/20190420_ljt_red_220_4/gamersky_010origin_019_20194201659245.jpg'
37 )
38 ];
View Code
void main() => runApp(App());
这里是main函数的箭头函数写法,runApp()的参数是一个widget,例如,这里的参数是App类的实例,因此可以推断,App类是Widget类的继承。
widget可以翻译为组件、部件,整个flutter应用就是由一个个widget组成的。
当一个类继承自widget部件的时候,要重写它的build方法,而这个build方法的返回值也是一个widget。就像上面的App类一样。
1 class App extends StatelessWidget {
2 @override
3 Widget build(BuildContext context) {
4 return MaterialApp(
5 home: Home(),
6 theme: ThemeData(
7 primarySwatch: Colors.red
8 ),
9 );
10 }
11 }
因此,可以推断出,MaterialApp也是一个widget。但是我们可以看到,代码段中并没有定义MaterialApp类,因此可以推断出,他是package:flutter/material.dart中导入的widget。
根据我目前的学习,widget分为两种,StatelessWidget和StatefulWidget,大概是说,前者是无状态的(静态的,内容不会发生改变),而后者是有状态的,内容可以动态变化。
ListView
在本例的Home部件中,返回了一个Scaffold部件作为MaterialApp的home属性的值。其中,设置了backgroundColor属性为灰色和appBar,一个内容为Hello的导航栏,且导航栏的阴影大小为4.0,如果想设计成扁平化风格,还可以把elevation的值设为0。
1 @override
2 Widget build(BuildContext context) {
3 // TODO: implement build
4 return Scaffold(
5 backgroundColor: Colors.grey[200],
6 appBar: AppBar(
7 title: Text('Hello'),
8 elevation: 4.0,
9 ),
10 body: ListView.builder(
11 itemCount: posts.length,
12 itemBuilder: _listItemBuilder,
13 ),
14 );
15 }
其中主体部分是一个列表,在这里用的两个值 itemCount和 itemBuilder。
这里的 itemCount是这个 ListView的长度,且要小于等于真实的数量,否则会以找不到索引而报错。
itemBuilder的值应该是一个返回值是 widget的函数,在本例中是一个 container,一个 container包含一张图片,两行文字,和两个空高度作为分割文字的行高来使用。
1 Widget _listItemBuilder (BuildContext context, int index) {
2 return Container(
3 color: Colors.white,
4 margin: EdgeInsets.all(8.0),
5 child: Column(
6 children: <Widget>[
7 Image.network(posts[index].imageUrl),
8 SizedBox(height: 16.0),
9 Text(
10 posts[index].title,
11 style: Theme.of(context).textTheme.title,
12 ),
13 Text(
14 posts[index].author,
15 style: Theme.of(context).textTheme.subhead,
16 ),
17 SizedBox(height: 8.0),
18 ],
19 ),
20 );
21 }
注意,这个函数的第二个参数index,是从0迭代到 itemCount - 1。