Flutter Widget 简单入门
Flutter 是 Google 提出的跨平台开发框架,使用 Dart 语言,支持 Android,IOS 系统。Flutter 一个重要的概念即是——“万物皆控件(Widget)”,像Padding
,Center
等都是 Widget。
Widget 和 Android 中的 View 很相似但又有不同,Widget 一旦生成便“一成不变”,直到下一次因为 Widget 更改或者 state 更新而被重新创建(Flutter’s framework creates a new tree of widget instances.),而 View 则只会被drawn
一次,直到invalidate
方法被调用。
本文主要记录一下 Flutter 中两个重要的控件:StatelessWidget 和 StatefulWidget,以及 Flutter 开发的一些基础知识。
Flutter 基础知识
Flutter 以 Dart 开发,其工程基本的结构如下:
- android
- ios
- lib
- main.dart
- pubspec.yaml //Flutter 工程的配置信息
Flutter 项目启动后会首先加载/lib/main.dart
中的main()
方法。
一个标准的 material app 的 main.dart 内容如下:
import 'package:flutter/material.dart';
import './product_manager.dart';
main() => runApp(MyApp());//在 main() 方法中调用了 material 的 runApp() 方法,里面传入了要展示的 Widget——APP 的界面,相当于 Android 的 setContentView()
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.deepOrange
),
home: Scaffold(//脚手架,一个预制的 APP 界面结构,也可以使用自定义 Widget
appBar: AppBar(
title: Text("EasyList"),
),
body: ProductManager("Test"),//这里是自定义的控件,布局信息主要在这里展示
),
);
}
}
StatelessWidget & StatefulWidget
StatelessWidget 和 StateFulWidget 区别在于:前者一旦创建,状态便不会再更改,而后者则可以动态改变 State 从而使 flutter 改变其状态。但是两者都会在每一帧被 rebuild。
StatelessWidget
A
StatelessWidget
is just what it sounds like—a widget with no state information.
StatelessWidget 一旦创建便不会更改,其状态只和构造函数中的参数有关。下面是一个 StatelessWidget 示例,一般只需要重写其 build() 方法,返回要展示的控件即可:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CustomerWidget();//在这里构建一个页面并返回
}
}
StatefulWidget
StatefulWidget
has aState
object that stores state data across frames and restores it.
StatefulWidget 可以通过动态更改其包含的 State,从而使 flutter 在下一次更新界面时依据 state 更新 StateWidget,本质上还是更新了一个可以在多帧之间存活的 State,在下一帧更新控件。
下面是一个 StatefulWidget 的示例:
class ProductManager extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return ProductManagerState();
}
}
class ProductManagerState extends State<ProductManager> {
@override
Widget build(BuildContext context) {
return CustomerWidget();
}
}
可以注意到 StatefulWidget 重写了createState()
,而该方法返回了自定义的ProductManagerState
类对象,在该类中build()
方法实现和 StatelessWidget 中的方法类似,返回要展示的页面控件。
两者的不同之处在于,StatefulWidget 中可以调用setState()
,更改其相应的state
,以便告诉 flutter 在下一次 rebuild 的时候更新 UI。
StatelessWidget 要想实现动态更新其内容,可以在其外部包裹一层 StatefulWidget,通过 StatefulWidget 更改状态 state,将更改后的 state 传给 StatelessWidget,从而间接更新了 StatelessWidget 的状态。
可以通过对该方法就行包装,使得在 StatelessWidget 控件中调用 StatefulWidget 控件的setState()
方法,达到刷新页面的效果:
// StatefulWidget
void aFun(){
setState(() {
// update UI
});
}
AStatelessWidget(aFun);// 将该方法传入 StatelessWidget 中
// StatelessWidget
final Function aFun
AStatelessWidget(this.aFun);// 接收传入的方法
aFun();// 执行该方法,从而实现调用 StatelessWidget 中的方法也可以刷新 UI
与 Android 的对比
Intent
Android 的 Intent 有两个主要作用:
- Activity 间跳转
- 组件间传递数据
Flutter 对此相应:
- 使用 Navigator 和
Route
s 实现在同一个“Activity”中不同的界面间( “screen”or“page”)跳转(push,pop),Navigator 类似于 Android 中的 Activity 栈。 - 通过 Android 原生 Intent 组件获取到其他 App 传来的数据,然后中通过下面的方法实现 Android 和 Flutter 交互:
示例代码:
//Android
MethodChannel(getFlutterView(), "app.channel.shared.data")
.setMethodCallHandler(MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.contentEquals("getSharedText")) {
result.success(sharedText);
sharedText = null;
}
}
});
//Flutter
class _SampleAppPageState extends State<SampleAppPage> {
static const platform = const MethodChannel('app.channel.shared.data');
String dataShared = "No data";
@override
void initState() {
super.initState();
getSharedText();
}
@override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: Text(dataShared)));
}
getSharedText() async {
var sharedData = await platform.invokeMethod("getSharedText");
if (sharedData != null) {
setState(() {
dataShared = sharedData;
});
}
}
}
线程
Flutter 是单线程的,他的线程和 Android 的 UI 线程绑定,在进行网络请求,IO 操作等时,可以使用sync/await
在执行完耗时操作后,再去更新 state 刷新 UI。
Since Flutter is single threaded and runs an event loop (like Node.js), you don’t have to worry about thread management or spawning background threads. If you’re doing I/O-bound work, such as disk access or a network call, then you can safely use async/await and you’re all set.
loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(dataURL);
setState(() {
widgets = json.decode(response.body);
});
}
而如果有特别频繁的 cpu 计算以至于能导致 UI 挂起,可以考虑使用Isolate
s 利用 CPU 多核心处理任务,但是这样就不能和主线程共享数据,通过ReceivePort
,SendPort
等传递数据。
Isolates(隔离) are separate execution threads that do not share any memory with the main execution memory heap. This means you can’t access variables from the main thread, or update your UI by calling
setState()
. Unlike Android threads, Isolates are true to their name, and cannot share memory (in the form of static fields, for example).
本地资源
截止 Flutter beta 2 仍然不能直接访问 Android assets 或者其他本地资源,但是 Android 可以访问 flutter 的 assets 资源:
val flutterAssetStream = assetManager.open("flutter_assets/assets/my_flutter_asset.png")
通过 Channel,flutter 可以间接访问 Android 资源,反之亦然。
主要是通过 Channel 完成,可以称之为隧道。主要是 MethodChannel 和 MessageChannel 两种,第一种是调用方法,第二种是传递信息。首先通信的双方是 Flutter 和本地操作系统或者应用,而且方法的调用和消息的方法可以从任何一方发起,类似 RPC(远程过程调用)。
作者:黄马
链接:掘金 https://juejin.im/post/5b35a75e51882574ea3a25e3
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
生命周期
Flutter 生命周期没有 Android 中那么“重要”,可以重写 didChangeAppLifecycleState()
监听。
inactive
— 应用处于非活动状态,不接受输入。iOSpaused
— 应用在后台运行,不可见,不接受输入。类似 Android 的onPause()
resumed
— 应用可见,并接受输入。类似 Android 的onPostResume()
suspending
— 应用请求暂停。类似 Android 的onStop()
布局
Flutter 有布局 Widget 如:
- Column 列
- Row 行
- Stack 左上角堆积,类似 FrameLayout
点击事件
FLutter 中的“onClick()
”: onPressed
,onTap
等等。
添加点击事件,在 Widget 外面添加一个GestureDetector
Widget:
GestureDetector(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row $i")),
onTap: () {
print('row tapped');
},
);
参考链接
Flutter Tutorial for Beginners - Build iOS and Android Apps with Google's Flutter & Dart