文章目录

1.Flutter生命周期

我们先了解下生命周期的概念,也就是一个页面对象从创建到销毁的整个状态管理。我们看下 Flutter 的 State 生命周期的示意图:

Flutter学习记录——14.生命周期_flutter

可以看到我们的一个页面在加载创建时需要执行:

构造函数 -> initState -> didChangeDependencies -> build 方法,然后才会渲染为一个页面。

当销毁关闭时:

deactivate -> dispose

内部的前后台页面状态变化主要有:

enum AppLifecycleState {
// 恢复可见
resumed,
// 不可见,后台运行,无法处理用户响应
inactive,
// 处在并不活动状态,无法处理用户响应。例如来电,画中画,弹框
paused,
// 应用被立刻暂停挂起,ios上不会回调这个状态
suspending,
}

当页面更新时会执行:

didUpdateWidget -> build

可能会调用多次。

那么接下来通过代码实例来了解 Flutter 的生命周期:

import 'package:flutter/material.dart';

class StateSamples extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return StateSamplesState();
}
}

class StateSamplesState extends State<StateSamples>
with WidgetsBindingObserver {
//插入渲染树时调用,只调用一次
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}

//构建Widget时调用
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LifeCycleState'),
),
body: Center(
child: Column(
children: <Widget>[],
),
),
);
}

//state依赖的对象发生变化时调用
@override
void didChangeDependencies() {
super.didChangeDependencies();
}

//组件状态改变时候调用,可能会调用多次
@override
void didUpdateWidget(StateSamples oldWidget) {
super.didUpdateWidget(oldWidget);
}

//当移除渲染树的时候调用
@override
void deactivate() {
super.deactivate();
}

//组件即将销毁时调用
@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}

//APP生命周期监听
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
//恢复可见
} else if (state == AppLifecycleState.paused) {
//处在并不活动状态,无法处理用户响应
//例如来电,画中画,弹框
} else if (state == AppLifecycleState.inactive) {
//不可见,后台运行,无法处理用户响应
} else if (state == AppLifecycleState.suspending) {
//应用被立刻暂停挂起,ios上不会回调
}
super.didChangeAppLifecycleState(state);
}

//其他方法

//热重载时调用
@override
void reassemble() {
super.reassemble();
}

//路由弹出
@override
Future<bool> didPopRoute() {
return super.didPopRoute();
}

//新的路由
@override
Future<bool> didPushRoute(String route) {
return super.didPushRoute(route);
}

//系统窗口相关改变回调,例如旋转
@override
void didChangeMetrics() {
super.didChangeMetrics();
}

//文字缩放大小变化
@override
void didChangeTextScaleFactor() {
super.didChangeTextScaleFactor();
}

//本地化语言变化
@override
void didChangeLocales(List<Locale> locale) {
super.didChangeLocales(locale);
}

//低内存回调
@override
void didHaveMemoryPressure() {
super.didHaveMemoryPressure();
}

//当前系统改变了一些访问性活动的回调
@override
void didChangeAccessibilityFeatures() {
super.didChangeAccessibilityFeatures();
}

//平台色调主题变化时
@override
void didChangePlatformBrightness() {
super.didChangePlatformBrightness();
}
}

2.Flutter按键监听

我们知道在 Android 或 iOS 平台上,手机上或遥控器上的一些实体按键是可以被监听到的,可以执行相关操作,当然 Flutter 上也可以进行按键监听。

首先看下返回键的监听,返回键监听拦截在 Flutter 中比较不一样。是单独使用一个组件:WillPopScope。

然后通过一个实例来看下 Flutter 中实现连按两次返回键退出的效果:

class KeyListenerState extends State<KeyListenerSamples> {
int last = 0;
int index = 0;

@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
// 要用WillPopScope包裹
return WillPopScope(
// 编写onWillPop逻辑
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text('KeyListener Demo'),
),
body: Center(
child: Text("按键监听"),
)),
);
}

// 返回键拦截执行方法
Future<bool> _onWillPop() {
int now = DateTime.now().millisecondsSinceEpoch;
print(now - last);
if (now - last > 1000) {
last = now;
// showToast("再按一次返回键退出");
return Future.value(false); //不退出
} else {
return Future.value(true); //退出
}
}
}

那么其他按键的监听使用的是 RawKeyboardListener。

RawKeyboardListener 继承自 StatefulWidget。

const RawKeyboardListener({
Key key,
// 焦点节点
@required this.focusNode,
// RawKeyEvent,按键事件
@required this.onKey,
// 子控件
@required this.child,
})

我们再看下 RawKeyEvent 的构造方法:

const RawKeyEvent({
// RawKeyEventData
@required this.data,
this.character,
})

监听 Android 平台使用 RawKeyEventDataAndroid,监听 Fuchsia 平台使用RawKeyEventDataFuchsia,iOS 平台暂时还没有发布。

RawKeyboardListener 用法:

class KeyListenerState extends State<KeyListenerSamples> {
FocusNode focusNode = FocusNode();

@override
void initState() {
super.initState();
FocusScope.of(context).requestFocus(focusNode);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('RawKeyboardListener Demo'),
),
// RawKeyboardListener包裹
body: RawKeyboardListener(
// 可以监听到的前提是有焦点,我们可以让组件先获取焦点
focusNode: focusNode,
onKey: (RawKeyEvent event) {
// 这里是监听Android平台按键,并且是KeyDown事件
if (event is RawKeyDownEvent &&
event.data is RawKeyEventDataAndroid) {
RawKeyDownEvent rawKeyDownEvent = event;
RawKeyEventDataAndroid rawKeyEventDataAndroid =
rawKeyDownEvent.data;
print("keyCode: ${rawKeyEventDataAndroid.keyCode}");
switch (rawKeyEventDataAndroid.keyCode) {
// 这里面的KeyCode值和Android平台的一致
case 19: //KEY_UP
break;
case 20: //KEY_DOWN
break;
case 21: //KEY_LEFT

break;
case 22: //KEY_RIGHT

break;
case 23: //KEY_CENTER
break;
default:
break;
}
}
},
child: Center(
child: Text("按键监听"),
)),
);
}
}

当然我们也可以把 RawKeyboardListener 应用在输入框的焦点获取和监听上。

3.总结

本节课主要是给大家讲解了 Flutter 的生命周期和按键监听的用法和特点。主要注意点和建议如下:

  • 重点掌握 Flutter 生命周期的几个状态和返回键的拦截处理的用法。
  • 尝试编写监听输入框的按键事件和焦点事件。