本节内容
-
- Flutter 应用程序的基本结构
-
- 查找和使用第三方库
-
- 使用热重载加快开发周期
-
- 添加一个动态改变状态的控件
-
- 如何创建一个无限滑动的 ListView
-
- 添加交互
-
- 界面跳转
-
- 使用主题更改应用程序的外观
1. 创建起始 Flutter 应用程序
1. 删除 lib / main.dart 中的所有代码并替换为如下代码
它在屏幕的中心显示 "Hello World"
//其实是 dart 语言
import 'package:flutter/material.dart';
void main() => runApp(new MyApp()); //使用 => 表示单行函数或方法的简写
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
child: new Text('Hello World'),
),
),
);
}
}
运行程序,可以看到如下效果:
Material 是一种视觉设计语言,这里使用 Flutter 创建了一个 Material 应用程序。
2. flutter 程序解析
- MyApp 继承了使应用程序本身成为小部件的 StatelessWidget,在Flutter中,几乎所有东西都是一个小部件,包括对齐,填充和布局
- StatelessWidget 是 immutable(不变的),即所有属性都不可变,是 final 的
- Material library 中的 Scaffold 控件提供了提供了默认的 app bar,其中的 body 属性可以包含主屏幕中的控件树
- 一个 Widget 提供一个 build() 方法,其工作就是描述如何显示子控件
- MyApp 中包含了一个 Center Widget,而 Center Widget 使其子控件树居中对齐
2. 查找和使用第三方库
开源库仓库:https://pub.dartlang.org/flutter/
1. 添加依赖
在 pubspec.yaml 中添加要依赖的第三方库,例如 english_words 3.1.0:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.0
english_words: ^3.1.0
2. 获取新的库 Packages Get
点击后可看到如下日志:
flutter packages get
Running "flutter packages get" in startup_namer...
Process finished with exit code 0
3. 升级第三方库:Packages upgrade
F:\Flutter\flutter\bin\flutter.bat --no-color packages upgrade
Running "flutter packages upgrade" in flutter_app...
Process finished with exit code 0
4. 导入第三方库
在 lib / main.dart 中,添加 import english_words,如下:
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
AS 会自动提示
5. 使用第三方库 english_words
使用英文单词包来生成文本,而不是使用字符串“Hello World”,代码如下:
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final wordPair = new WordPair.random();
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
//child: new Text('Hello World'), // Replace the highlighted text...
child: new Text(wordPair.asPascalCase), // With this highlighted text.
),
),
);
}
}
3. 使用热重载加快开发周期
如果应用程序正在运行,则使用热重新加载按钮(闪电图标)更新正在运行的应用程序。每次单击热重新加载或保存项目时,都会在正在运行的应用程序中随机选择一个不同的单词对。
因为单词对是在 build() 方法中进行的,每次运行 build() 方法都会重新执行
注意:如果应用进程存在但是应用程序不在前台,则|> 运行按钮和 HotLoad 按钮都不会重新启动应用(即点击没反应),需要先手动打开应用才行
4. 添加一个动态改变状态的控件
相对于不变的 Stateless widget,Stateful widgets 是状态可变的
实现 Stateful widgets 需要两个类:StatefulWidget 类和一个 State 类
1. 创建 StatefulWidget 子类
一般将 StatefulWidget 的子类实现放到文件末尾,其内部只创建了一个 State 类
class RandomWords extends StatefulWidget {
@override
createState() => new RandomWordsState();
}
2. 创建 State 子类
在 State 子类中保持 RandomWords widget 的状态
class RandomWordsState extends State {
@override
Widget build(BuildContext context) {
final wordPair = new WordPair.random();
return new Text(wordPair.asPascalCase);
}
}
3. 修改 MyApp 中的 body 代码
将之前的 new Text(wordPair.asPascalCase)
替换为 new RandomWords()
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//final wordPair = new WordPair.random(); // Delete this line
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
//child: new Text(wordPair.asPascalCase), // Change the highlighted text to...
child: new RandomWords(), // ... this highlighted text
),
),
);
}
}
4. 运行 Flutter App
5. 如何创建一个无限滑动的 ListView
1. 准备 ListView 的数据
dart 语言中使用 _ 作为前缀来表示私有变量
class RandomWordsState extends State {
final _suggestions = [];//使用 _suggestions 来存储 lsitView 数据
final _biggerFont = const TextStyle(fontSize: 18.0); //使用 _biggerFont 来使字体更大
...
}
2. 创建无限滑动的 ListView
在 RandomWordsState 类中添加 _buildSuggestions()
方法来显示 ListView
该方法中的 itemBuilder 使用匿名函数,形参是 context 和 position,position 从 0 开始,一旦用户滑动该匿名方法就会被调用,并且 position 不断增加
class RandomWordsState extends State {
...
Widget _buildSuggestions() {
return new ListView.builder(
padding: const EdgeInsets.all(16.0),
// The itemBuilder callback is called once per suggested word pairing,
// and places each suggestion into a ListTile row.
// For even rows, the function adds a ListTile row for the word pairing.
// For odd rows, the function adds a Divider widget to visually
// separate the entries. Note that the divider may be difficult
// to see on smaller devices.
itemBuilder: (context, i) {
// Add a one-pixel-high divider widget before each row in theListView.
if (i.isOdd) return new Divider();
// i ~/ 2 表示整除,例如 1, 2, 3, 4, 5 变成 0, 1, 1, 2, 2.
final index = i ~/ 2;
// 加载更多
if (index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
}
);
}
}
3. 创建 item 布局
在 RandomWordsState 中添加 _buildRow() 方法用于创建 item
class RandomWordsState extends State {
...
Widget _buildRow(WordPair pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
}
}
4. 调用创建 listView 的方法
class RandomWordsState extends State {
...
@override
Widget build(BuildContext context) {
// final wordPair = new WordPair.random(); // Delete these two lines.
// return new Text(wordPair.asPascalCase);
return new Scaffold (
appBar: new AppBar(
title: new Text('Startup Name Generator'),
),
body: _buildSuggestions(),
);
}
...
}
5. 移除 MyApp 中的无用控件
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
home: new RandomWords(),
);
}
}
6. 添加交互
1. 新建 list 集合保存用户喜欢的 item
class RandomWordsState extends State {
final _suggestions = [];
//使用 _saved 集合来保存状态
final _saved = new Set();
final _biggerFont = const TextStyle(fontSize: 18.0);
...
}
2. 新建成员变量来判断 item 是否添加到了喜欢列表
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);
...
}
3. 添加喜欢的心型 icon
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
);
}
4. 添加点击事件
在 Flutter 中,调用 setState() 会再次触发 build() 方法,从而更新 UI
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
onTap: () {
//调用 setState() 方法并传入一个匿名函数
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
}
7. 界面跳转
在 Flutter 中,Navigator 使用栈管理各个界面
1. 添加 Navigation 导航 icon
class RandomWordsState extends State {
...
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Startup Name Generator'),
// 一个属性如果有多个控件,则可以用 [] 来表示
actions: [
new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
void _pushSaved() {}
...
}
2. 点击导航 icon 时新建界面
使用 MaterialPageRoute 新建界面
void _pushSaved() {
Navigator.of(context).push(
new MaterialPageRoute(
builder: (context) {
// 创建已选中的 item
final tiles = _saved.map(
(pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
// divideTiles 为 tiles 添加分割线
final divided = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList();
//创建 Scaffold 并添加 appBar 和 listView 作为新界面
return new Scaffold(
appBar: new AppBar(
title: new Text('Saved Suggestions'),
),
body: new ListView(children: divided),
);
},
),
);
}
3. 运行效果
8. 使用主题更改应用程序的外观
1. 使用 ThemeData 类改变主题
改变 MyApp 的主题为白色
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
theme: new ThemeData(
primaryColor: Colors.white,
),
home: new RandomWords(),
);
}
}