赞
踩
这是个系列文章,后面还有很多篇,希望对大家能有帮助。
Flutter 是 Google 推出的移动端跨平台开发框架,使用的编程语言是 Dart。从 React Native 到 Flutter,开发者对跨平台解决方案的探索从未停止,毕竟,它可以让我们节省移动端一半的人力。本篇文章中,我们就通过编写一个简单的 Flutter 来了解他的开发流程。
这里我们要开发的 demo 很简单,只是在屏幕中间放一个按钮,点击的时候,模拟摇两个骰子并弹窗显示结果。我们撸起袖子开干吧。
我们这里假定读者已经安装好 Flutter,并且使用安装了 Flutter 插件的 Android Studio 进行开发。如果你还没有配置好开发环境,可以参考玉刚的 这篇文章。
下面我们开始创建项目:
第一次创建项目时,由于要下载 gradle,时间会稍微长一些。
在上一小节里我们所创建的项目,已经有了一些代码,感兴趣的读者可以跑到自己手机上看一看,相关的代码在 lib/main.dart 里面。
为了体验从头开发一个应用的过程,这里我们先把 lib/main.dart 里的内容都删除。
首先,创建一个 main
函数。跟其他语言一样,main
函数是应用的入口:
void main() {
}
下面我们编写一个 Widget
作为我们的 app。在 Flutter 里,所有的东西都是 Widget
。
import 'package:flutter/material.dart';
void main() {
// 创建一个 MyApp
runApp(MyApp());
}
/// 这个 widget 作用这个应用的顶层 widget.
///
/// 这个 widget 是无状态的,所以我们继承的是 [StatelessWidget].
/// 对应的,有状态的 widget 可以继承 [StatefulWidget]
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 创建内容
}
}
现在我们进入正题,实现一个按钮,在点击的时候弹框显示结果:
@override Widget build(BuildContext context) { // 我们想使用 material 风格的应用,所以这里用 MaterialApp return MaterialApp( // 移动设备使用这个 title 来表示我们的应用。具体一点说,在 Android 设备里,我们点击 // recent 按钮打开最近应用列表的时候,显示的就是这个 title。 title: 'Our first Flutter app', // 应用的“主页” home: Scaffold( appBar: AppBar( title: Text('Flutter rolling demo'), ), // 我们知道,Flutter 里所有的东西都是 widget。为了把按钮放在屏幕的中央, // 这里使用了 Center(它是一个 widget)。 body: Center( child: RaisedButton( // 用户点击时候调用 onPressed: _onPressed, child: Text('roll'), ), ), ), ); } void _onPressed() { // TODO }
现在,点击 Run,把我们的第一个 Flutter 应用跑起来吧。没有意外的话,你会看到下面这个页面:
如果你遇到了什么困难,可以查看 tag first_app_step1 的代码:
git clone https://github.com/Jekton/flutter_demo.git
cd flutter_demo
git checkout first_app_step1
由于是第一次写 Flutter 应用,我们对上面的代码是否能够按照预期执行还不是那么有信心,所以我们先打个 log 确认一下,点击按钮后是不是真的会执行 onPress
。
打 log 可以使用 Dart 提供的 print
,但在日志比较多的时候,print
的输出可能会被 Android 丢弃,这个时候 debugPrint
会是更好的选择。对应的日志信息可以在 Dart Console 里查看(View -> Tool Windows -> Run 或者 Mac 上使用 Command+4 打开)。
void _onPressed() {
debugPrint('_onPressed');
}
保存后(会自动 Hot Reload),我们再次点击按钮,在我的设备上,打印出了下面这样的信息:
I/flutter (11297): _onPressed
V/AudioManager(11297): playSoundEffect effectType: 0
V/AudioManager(11297): querySoundEffectsEnabled...
这里的第一行,就是我们打的。现在我们有足够的自信说,点击按钮后,会执行 _onPressed
方法了。
软件开发通常是一个螺旋式上升的过程,不可能通过一次编码、调试就完成。现在,我们开始第二轮迭代。
接下来要做的,便是在 _onPressed
里面弹一个框:
// context 这里使用的是 MyApp.build 的参数
void _onPressed(BuildContext context) {
debugPrint('_onPressed');
showDialog(
context: context,
builder: (_) {
return AlertDialog(
content: Text('AlertDialog'),
);
}
);
}
遗憾的是,这一次并不那么顺利。Dialog 没有弹出来,而且报了下面这问题:
I/flutter (11297): Navigator operation requested with a context that does not include a Navigator.
I/flutter (11297): The context used to push or pop routes from the Navigator must be that of a widget that is a
I/flutter (11297): descendant of a Navigator widget.
原因在于,stateless 的 widget
只能用于显示信息,不能有其他动作。所以,该让 StatefulWidget
上场了。
class RollingButton extends StatefulWidget { // StatefulWidget 需要实现这个方法,返回一个 State @override State createState() { return _RollingState(); } } // 可能看起来有点恶心,这里的泛型参数居然是 RollingButton class _RollingState extends State<RollingButton> { @override Widget build(BuildContext context) { return RaisedButton( child: Text('Roll'), onPressed: _onPressed, ); } void _onPressed() { debugPrint('_RollingState._onPressed'); showDialog( // 第一个 context 是参数名,第二个 context 是 State 的成员变量 context: context, builder: (_) { return AlertDialog( content: Text('AlertDialog'), ); } ); } }
要实现一个 stateful 的 widget
,可以继承 StatefulWidget
并在 createState
方法中返回一个 State
。除了这一部分,代码跟我们之前写的并没有太大的区别。
剩下的,就是替换 MyApp
里面使用的按钮,修改后的代码如下:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Our first Flutter app', home: Scaffold( appBar: AppBar( title: Text('Flutter rolling demo'), ), body: Center( child: RollingButton(), ), ), ); } }
再次运行,点击按钮后,我们将看到梦寐以求的 dialog。
如果你遇到了麻烦,可以查看 tag first_app_step2 的代码。
最后,我们来实现“roll”:
import 'dart:math';
class _RollingState extends State<RollingButton> {
final _random = Random();
// ...
图片转存中...(img-iPQf2rFe-1630928216037)]
如果你遇到了麻烦,可以查看 tag first_app_step2 的代码。
最后,我们来实现“roll”:
import ‘dart:math’;
class _RollingState extends State {
final _random = Random();
// …
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。