context: context,
    barrierDismissible: false,
    builder:(_) {
      return WillPopScope(
        onWillPop: () async {
          // 拦截到返回键,证明dialog被手动关闭
          _isShowDialog = false;
          return Future.value(true);
        },
        child: ProgressDialog(hintText: "正在加载..."),
      );
    }
  );
}

}


本问题详细的代码见:[点击查看](https://gitee.com/vip204888/android-p7)

3.addPostFrameCallback
----------------------

`addPostFrameCallback`回调方法在Widget渲染完成时触发,所以一般我们在获取页面中的Widget大小、位置时使用到。

前面第二点我有说到我会在接口请求前弹出loading。如果我将请求方法放在了`initState`方法中,异常如下:

> inheritFromWidgetOfExactType(/_InheritedTheme) or inheritFromElement() was called before initState() completed. When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget. Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.

原因:弹出一个DIalog的`showDialog`方法会调用`Theme.of(context, shadowThemeOnly: true)`,而这个方法会通过`inheritFromWidgetOfExactType`来跨组件获取Theme对象。

![在这里插入图片描述](https://s2.51cto.com/images/20210827/1630063884393166.jpg)

`inheritFromWidgetOfExactType`方法调用`inheritFromElement`:

![在这里插入图片描述](https://s2.51cto.com/images/20210827/1630063885624014.jpg)

但是在`_StateLifecycle`为`created` 和 `defunct` 时是无法跨组件拿到数据的,也就是`initState()`时和`dispose()`后。所以错误信息提示我们在 `didChangeDependencies` 调用。

然而放在`didChangeDependencies`后,新的异常:

> setState() or markNeedsBuild() called during build. This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.

提示我们页面在build时不能调用`setState()` 或 `markNeedsBuild()`方法。所以我们需要在build完成后,才可以去创建这个新的组件(这里就是Dialog)。

所以解决方法就是使用`addPostFrameCallback`回调方法,等待页面build完成后在请求数据:

@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_){
/// 接口请求
});
}


导致这类问题的场景很多,但是大体解决思路就是上述的办法。

本问题详细的代码见:[点击查看](https://gitee.com/vip204888/android-p7)

4.删除emoji
---------

不多哔哔,直接看图:

![](https://s2.51cto.com/images/20210827/1630063886351528.jpg)

简单说就是删除一个emoji表情,一般需要点击删除两次。碰到个别的emoji,需要删除11次!!其实这问题,也别吐槽Flutter,基本emoji在各个平台上都或多或少有点问题。

原因就是:

![在这里插入图片描述](https://s2.51cto.com/images/20210827/1630063886800938.jpg)

这个问题我发现在Flutter 的`1.5.4+hotfix.2`版本,解决方法可以参考:[github.com/flutter/eng…](https://gitee.com/vip204888/android-p7) 虽然只适用于长度为2位的emoji。

幸运的是在最新的稳定版`1.7.8+hotfix.3`中修复了这个问题。不幸的是我发现了其他的问题,比如在我小米MIX 2s上删除文字时,有时会程序崩溃,其他一些机型正常。异常如下图:

![](https://s2.51cto.com/images/20210827/1630063887463510.jpg)

我也在Flutter上发现了同样的问题Issue,具体情况可以关注这个Issue :[github.com/flutter/flu…](https://gitee.com/vip204888/android-p7) ,据Flutter团队的人员的回复,这个问题修复后不太可能进入1.7的稳定版本。。

![在这里插入图片描述](https://s2.51cto.com/images/20210827/1630063888816912.jpg)

所以建议大家谨慎升级,尤其是用于生产环境。那么这个问题暂时只能搁置下来了,等待更稳定的版本。。。

**19.07.20更新**,官方发布了`1.7.8+hotfix.4`,修复了此问题。经过测试问题修复,大家可以放心使用了。

![在这里插入图片描述](https://s2.51cto.com/images/20210827/1630063888963601.jpg)

5.键盘
----

### 1.是否弹起

MediaQuery.of(context).viewInsets.bottom > 0


`viewInsets.bottom`就是键盘的顶部距离底部的高度,也就是弹起的键盘高度。如果你想实时过去键盘的弹出状态,配合使用`didChangeMetrics`。完整如下:

import ‘package:flutter/material.dart’;

typedef KeyboardShowCallback = void Function(bool isKeyboardShowing);

class KeyboardDetector extends StatefulWidget {

KeyboardShowCallback keyboardShowCallback;

Widget content;

KeyboardDetector({this.keyboardShowCallback, @required this.content});

@override
_KeyboardDetectorState createState() => _KeyboardDetectorState();
}

class _KeyboardDetectorState extends State<KeyboardDetector>
with WidgetsBindingObserver {br/>@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}

@override
void didChangeMetrics() {
super.didChangeMetrics();
WidgetsBinding.instance.addPostFrameCallback((_) {
print(MediaQuery.of(context).viewInsets.bottom);
setState(() {
widget.keyboardShowCallback
?.call(MediaQuery.of(context).viewInsets.bottom > 0);
});
});
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
Widget build(BuildContext context) {
return widget.content;
}
}

代码来自项目GSYFlutterDemo:https://github.com/CarGuo/GSYFlutterDemo


### 2.弹出键盘

if (MediaQuery.of(context).viewInsets.bottom == 0){
final focusScope = FocusScope.of(context);
focusScope.requestFocus(FocusNode());
Future.delayed(Duration.zero, () => focusScope.requestFocus(_focusNode));
}


其中`_focusNode`是对应的`TextField`的`focusNode`属性。

### 3.关闭键盘

FocusScope.of(context).requestFocus(FocusNode());
/// 1.7.8 开始推荐以下方式(https://github.com/flutter/flutter/issues/7247
FocusScope.of(context).unfocus();


这里提一下关闭,一般来说即使键盘弹出,点击返回页面关闭,键盘就会自动收起。但是顺序是:

页面关闭 --> 键盘关闭

这样会导致键盘短暂的出现在你的上一页面,也就会出现短暂的部件溢出(关于溢出可见[上篇](https://gitee.com/vip204888/android-p7))。

![](https://s2.51cto.com/images/20210827/1630063889396789.jpg)

所以这时你就需要在页面关闭前手动调用关闭键盘的代码了。按道理是要放到`deactivate`或者`dispose`中处理的,可谁让`context`已经为null了,所以,老办法,拦截返回键:

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// 拦截返回键
FocusScope.of(context).unfocus();
return Future.value(true);
},
child: Container()
);
}


当然如果你是自己代码调用的返回,可以在返回页面之前关闭键盘:

FocusScope.of(context).unfocus();
Navigator.pop(context);



本问题详细的代码见:[点击查看](https://gitee.com/vip204888/android-p7)

### 最后

跳槽季整理面试题已经成了我多年的习惯!**在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。**

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

![](https://s2.51cto.com/images/20210827/1630063890392858.jpg)

**本文在开源项目:[【腾讯文档 】](https://gitee.com/vip204888/android-p7)中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…**