一、第一个Flutter程序

创建好Flutter项目后,修改入口文件。

main.dart

  1. import 'package:flutter/material.dart';
  2. void main() => runApp(new MyApp());
  3. class MyApp extends StatelessWidget {
  4. @override
  5. Widget build(BuildContext context) {
  6. return new MaterialApp(
  7. title: 'Flutter Demo',
  8. theme: new ThemeData(
  9. primarySwatch: Colors.blue,
  10. ),
  11. home: new Scaffold(
  12. appBar: new AppBar(
  13. title: new Text('Welcome to Flutter'),
  14. ),
  15. body: new Center(
  16. child: new Text('Hello World'),
  17. ),
  18. ),
  19. );
  20. }
  21. }

第一句:

  1. void main() => runApp(new MyApp());

是以下简写:

  1. void main() {
  2. runApp(new MyApp());
  3. }

main 函数使用了 => 符号, 这是Dart中单行函数或方法的简写。

MyApp 继承自 StatelessWidget,widget的主要工作是提供一个 build() 方法来描述如何根据其他较低级别的widget来显示自己。

001.png

二、框架

应用

创建一个 MaterialApp 应用程序, 常用的属性有:

  • debugShowCheckedModeBanner: false 是否显示 Debug 字样, 默认 true
  • theme: ThemeData.dark() 应用程序主题
  • title: title 应用程序标题
  • home: Scaffold(...) 应用程序首页, 通常使用 Scaffold 脚手架搭建

主题

ThemeData 用于定义主题样式(背景颜色、字体大小、字体颜色等)。

  1. MaterialApp(
  2. ...
  3. theme: new ThemeData(
  4. primaryColor: Color(0xff1ABC9C),
  5. appBarTheme: AppBarTheme(
  6. color: Color(0xff1ABC9C),
  7. actionsIconTheme: IconThemeData(
  8. color: Colors.white
  9. ),
  10. iconTheme: IconThemeData(
  11. color: Colors.white
  12. ),
  13. textTheme: TextTheme(
  14. title: TextStyle(
  15. color: Colors.white,
  16. fontSize: 20
  17. )
  18. )
  19. ),
  20. ),
  21. );

也可使用内置主题:

  1. theme: ThemeData.dark()

页面骨架

一个完整的数路由页可能会包含导航栏、抽屉菜单(Drawer)以及底部 Tab 导航菜单等。如果每个路由页面都需要开发者自己手动去实现这些,这会是一件非常麻烦且无聊的事。幸运的是,Flutter Material Scaffold 是一个路由页的骨架,我们使用它可以很容易地拼装出一个完整的页面。

常用的属性有:

  • appBar: AppBar() 导航栏
  • body: Widget... 主要内容
  • drawer: Drawer() 抽屉
  • floatingActionButton: FloatingActionButton() 悬浮按钮
  • bottomNavigationBar: BottomAppBar() 底部导航栏

导航栏

AppBar:定义导航栏。

AppBar 的定义:

  1. AppBar({
  2. Key key,
  3. this.leading, // 导航栏左侧Widget
  4. this.actions, // 导航栏右侧Widget
  5. this.title,// 页面标题
  6. this.bottom, // 导航栏底部菜单,通常为Tab按钮组
  7. this.elevation = 4.0, // 导航栏阴影
  8. this.centerTitle, //标题是否居中
  9. this.automaticallyImplyLeading = true, //如果leading为null,是否自动实现默认的leading按钮
  10. this.backgroundColor,
  11. ... //其它属性见源码注释
  12. })

比如:
005.png

  1. appBar: new AppBar(
  2. title: new Text(title),
  3. leading: IconButton(icon: Icon(Icons.dashboard), onPressed: () {}),
  4. actions: <Widget>[ //导航栏右侧菜单
  5. IconButton(icon: Icon(Icons.share), onPressed: () {}),
  6. ],
  7. ),

悬浮按钮

FloatingActionButton 是 Material 设计规范中的一种特殊 Button,通常悬浮在页面的某一个位置作为某种常用动作的快捷入口
004.png

  1. floatingActionButton: new FloatingActionButton(
  2. onPressed: _incrementCounter,
  3. tooltip: 'Increment',
  4. child: new Icon(Icons.add),
  5. ),
  6. // 指定 floatingActionButton 的位置
  7. floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

侧边抽屉

Drawer:侧边抽屉
007.gif

  1. drawer: Drawer(
  2. child: Column(
  3. crossAxisAlignment: CrossAxisAlignment.start,
  4. children: <Widget>[
  5. Padding(
  6. padding: const EdgeInsets.only(top: 38.0),
  7. child: Row(
  8. children: <Widget>[
  9. Padding(
  10. padding: const EdgeInsets.symmetric(horizontal: 16.0),
  11. child: ClipOval(
  12. child: Image.asset(
  13. "assets/imgs/avatar.png",
  14. width: 80,
  15. height: 80,
  16. ),
  17. ),
  18. ),
  19. Text(
  20. "Quanzaiyu",
  21. style: TextStyle(fontWeight: FontWeight.bold),
  22. )
  23. ],
  24. ),
  25. ),
  26. Expanded(
  27. child: ListView(
  28. children: <Widget>[
  29. ListTile(
  30. leading: const Icon(Icons.add),
  31. title: const Text('Add account'),
  32. ),
  33. ListTile(
  34. leading: const Icon(Icons.settings),
  35. title: const Text('Manage accounts'),
  36. ),
  37. ],
  38. ),
  39. ),
  40. ],
  41. ),
  42. ),

底部导航栏

BottomAppBar
005.png

  1. bottomNavigationBar: BottomAppBar(
  2. color: Colors.grey, // 背景色
  3. child: Container(
  4. height: 50.0,
  5. child: Row(
  6. mainAxisAlignment: MainAxisAlignment.spaceAround,
  7. children: <Widget>[
  8. IconButton(
  9. iconSize: 24,
  10. icon: Icon(Icons.home, size: 36, color: Colors.blue,),
  11. tooltip: 'home',
  12. onPressed: () {},
  13. ),
  14. IconButton(
  15. iconSize: 24,
  16. icon: Icon(Icons.settings, size: 36, color: Colors.green,),
  17. tooltip: 'settings',
  18. onPressed: () {},
  19. )
  20. ],
  21. ),
  22. ),
  23. ),

BottomNavigationBar
006.gif

  1. int _selectedIndex = 0;
  2. bottomNavigationBar: BottomNavigationBar(
  3. items: const <BottomNavigationBarItem>[
  4. BottomNavigationBarItem(
  5. icon: Icon(Icons.home),
  6. title: Text('Home'),
  7. ),
  8. BottomNavigationBarItem(
  9. icon: Icon(Icons.business),
  10. title: Text('Business'),
  11. ),
  12. BottomNavigationBarItem(
  13. icon: Icon(Icons.school),
  14. title: Text('School'),
  15. ),
  16. ],
  17. currentIndex: _selectedIndex,
  18. selectedItemColor: Colors.amber[800],
  19. onTap: (int index) {
  20. setState(() {
  21. _selectedIndex = index;
  22. });
  23. },
  24. ),

参考:

其他

三、使用外部包

pubspec.yaml 中加入 english_words

  1. dependencies:
  2. flutter:
  3. sdk: flutter
  4. cupertino_icons: ^0.1.0
  5. english_words: ^3.1.0

使用以下命令更新包:

  1. flutter packages get

修改 main.dart

  1. import 'package:flutter/material.dart';
  2. import 'package:english_words/english_words.dart';
  3. void main() {
  4. runApp(new MyApp());
  5. }
  6. class MyApp extends StatelessWidget {
  7. @override
  8. Widget build(BuildContext context) {
  9. return new MaterialApp(
  10. title: 'Flutter Demo',
  11. theme: new ThemeData(
  12. primarySwatch: Colors.blue,
  13. ),
  14. home: new Scaffold(
  15. appBar: new AppBar(
  16. title: new Text('Welcome to Flutter'),
  17. ),
  18. body: new Center(
  19. child: new RandomWordsWidget(),
  20. ),
  21. ),
  22. );
  23. }
  24. }
  25. class RandomWordsWidget extends StatelessWidget {
  26. @override
  27. Widget build(BuildContext context) {
  28. // 生成随机字符串
  29. final wordPair = new WordPair.random();
  30. return Padding(
  31. padding: const EdgeInsets.all(8.0),
  32. child: new Text(wordPair.toString()),
  33. );
  34. }
  35. }

以上, 使用 new WordPair.random() 随机生成英文单词, 通过 wordPair.toString() 将之转化为字符串

还可使用 wordPair.asPascalCase 生成驼峰形式的单词

Pub仓库

Pub 是Google官方的Dart Packages仓库,类似于node中的npm仓库,android中的jcenter。我们可以在Pub上面查找我们需要的包和插件,也可以向Pub发布我们的包和插件。我们将在后面的章节中介绍如何向Pub发布我们的包和插件。

四、事件处理

单击

  • onTapDown 指针已经在特定位置与屏幕接触
  • onTapUp 指针停止在特定位置与屏幕接触
  • onTap tap事件触发
  • onTapCancel 先前指针触发的onTapDown不会在触发tap事件

双击

  • onDoubleTap 用户快速连续两次在同一位置轻敲屏幕.

长按

  • onLongPress 指针在相同位置长时间保持与屏幕接触

垂直拖动

  • onVerticalDragStart 指针已经与屏幕接触并可能开始垂直移动
  • onVerticalDragUpdate 指针与屏幕接触并已沿垂直方向移动.
  • onVerticalDragEnd 先前与屏幕接触并垂直移动的指针不再与屏幕接触,并且在停止接触屏幕时以特定速度移动

水平拖动

  • onHorizontalDragStart 指针已经接触到屏幕并可能开始水平移动
  • onHorizontalDragUpdate 指针与屏幕接触并已沿水平方向移动
  • onHorizontalDragEnd 先前与屏幕接触并水平移动的指针不再与屏幕接触,并在停止接触屏幕时以特定速度移动

GestureDetector

很多组件都包含一些事件处理的属性, 比如 GestureDetector、ListView 等。

示例:GestureDetector 的使用

  1. new GestureDetector(
  2. onTapDown: _handleTapDown, // 处理按下事件
  3. onTapUp: _handleTapUp, // 处理抬起事件
  4. onTap: () {
  5. // ...
  6. },
  7. onTapCancel: _handleTapCancel,
  8. child: new Text('Click me!'),
  9. );

参考资料