我跟着官网Write your first Flutter app实践了一遍。
part1: Write your first Flutter app
part2: https://codelabs.developers.google.com/codelabs/first-flutter-app-pt2/#8
完整项目GitHub地址: https://github.com/skykywind/First-Flutter-App.git
First App
开发这个项目能够对Flutter开发有个大概的了解,之后可以更好地学习其他细节。
声明一下,本篇不是带你一步步实现这个例子,因为官网更适合去跟着实现。我写这篇的目的是为了总结这个项目所用到的一些基本知识。
官网这个简单的App 将实现一个为新公司起名字的功能,我们会引入一个english_words
第三方库来生成名字,向下拖拽滚动视图时,会生成更多新名字。 Part2则会添加收藏功能,点击导航按钮,可以跳转到新的页面查看收藏。
[图片上传失败...(image-a261bf-1559544689565)]
创建项目
我用的是Android Studio IDE,
- 选择 File > New Flutter Project;
- 项目类型选择 Flutter application, 然后下一步;
- 修改Project name,项目名称只能包含小写字母和下划线,确认SDK path 和Project location;
- 点击finish, 等待创建完成。
代码解读与分析
代码格式化
Android Studio / IntelliJ IDEA: 在编码区点击右键,选择Reformat Code with dartfmt
引入包的方式
- 在
pubspec.yaml
文件中添加依赖库:
...
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
#在这里引入 english_words
english_words: ^3.1.0
dev_dependencies:
flutter_test:
sdk: flutter
...
- 在调用文件中使用
import
导入:
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
关于StatelessWidget
和 StatefulWidget
Flutter中所有对象都被抽象成了Widget,比如视图组件,Layout,App本身,都是Widget:
- StatelessWidget,它的所有属性都是不可变的,用final修饰;
- StatefulWidget, 生命周期内,状态是可能发生改变的。实现StatefulWidget,至少需要2个类:
- 一个 StatefulWidget类。
- 一个 State类。这个类来维护Widget的状态。
main
函数
main.dart
的main函数是整个程序的入口:
void main() => runApp(MyApp());
main函数直接返回的是运行MyApp()示例,也就是运行我们的应用程序。
App是什么?
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Startup Name Generator',
theme: ThemeData(
primaryColor: Colors.deepPurpleAccent,
),
home: RandomWords(),
);
}
}
我们可以看到MyApp本身是一个StatelessWidget,通过build
方法构建内容上下文。这个Demo中使用MaterialApp
类构建了 Material
风格的应用。除了MaterialApp
,我们也可以使用Cupertino widgets,或者 Container
, Center
等等作为内容视图。
MaterialApp
这里调用了3个属性:
- title: 页面标题
- theme: 主题设置
- home: 页面内容,也就是导航之外的部分。这里home是一个StatefulWidget 的RandomWords类。
StatefulWidget 的使用
上面提到StatefulWidget 的使用2个类,Widget本身和State。
class RandomWords extends StatefulWidget {
@override
RandomWordsState createState() => RandomWordsState();
}
RandomWords
的实现很简单,只是重写createState()
方法,返回绑定的RandomWordsState
。
下面是RandomWordsState
的全部代码。
class RandomWordsState extends State<RandomWords> {
final List<WordPair> _suggestions = <WordPair>[];
final Set<WordPair> _saved = Set<WordPair>();
final _biggerFont = const TextStyle(fontSize: 18.0);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
actions: <Widget>[
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
Widget _buildSuggestions() {
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i) {
if (i.isOdd) return Divider();
final index = i ~/ 2;
if (index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
});
}
Widget _buildRow(WordPair pair) {
final bool alreadySaved = _saved.contains(pair);
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
onTap: () {
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
}
void _pushSaved() {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final List<Widget> divided = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList();
return Scaffold(
appBar: AppBar(
title: Text('Saved Suggestions'),
),
body: ListView(children: divided),
);
},
),);
}
}
看上去代码很多,但是实际上就几个方法:
-
Widget build(BuildContext context)
的方法创建头部导航。Scaffold
创建了顶部导航部分,其中添加了标题和一个图片按钮,按钮点击事件为push到下一个页面(_pushSaved()方法); -
Widget _buildSuggestions()
方法创建了一个ListView
,Widget _buildRow(WordPair pair)
方法为ListView创建ItemBuilder。 -
_suggestions
存储所有生成的建议名字,_saved
保存所有喜欢的名字。
总结
整个Demo可以让我们一揽Flutter开发App的每个步骤和概况,它是通过Widget组装的形式实现页面,每个组件都会有自己的属性可以进行自定义。
除此之外,这个Demo我们还学到如何引入第三方的包,如何使用StatelessWidget
和 StatefulWidget
。Material风格