今日这篇文章的目的是补全咱们关于 MediaQuery
和对应 rebuild 机制的根底认知,相信本篇内容对你优化功能和调试 bug 会很有协助。
Flutter 里咱们应该都离不开安全教育平台作业登录 MediafluttershyQuery
,比方经过 MediaQuery.of(context).size
获取屏幕巨细 ,或者经过 MediaQuery.o嵌套查询f(context).padding.top
获取状况栏高度,那随便运用 MediaQuery.of(contextappearance)
会有什么问题吗?
首先咱们需求简略解释一下,经过 MediaQuery.of
获取到的 MediaQueryData
里有几个很相似的参数:
-
viewInsets
: 被系统用户界面完全遮挡的部分巨细,简略来说便是键盘高度 -
padding
: 简略来说便是状况栏和底部安全区apple域,可是嵌套结构bottom
会由于键盘弹出变成 0 -
viewPadding
:flutter有必要学吗和padding
相同,可是bottom
部分不approach会产生改动
举个比方,在 iOS 上,如下图所示,在弹出键盘和未弹出键盘的情况下,能够看到 MediaQueryData
里一些参数的变化:缓存
-
viewInsets
在没有弹出键盘时是 0,弹出键盘之后bottFlutterom
变成 336 -
paddin缓存g
在弹apple出键盘的flutter是什么意思前后差异,bottom
从 34 变成了 0 -
viewPadding
在键盘弹出前后数据没有产生变化
能够看到
MediaQueryData
里的数据是会依据键盘状况产生变化,又由于MediaQuery
是一个InheritedWidget
,所以咱们能够经过MediaQue安全工程师ry.of(context)
获取到顶层同享的MediaQuery缓存视频合并Data
。
那么问题来了,InheritedWidget
的更新逻辑,是经过登记的 context
来绑定的,也便是 MediaQuery.of(context)
本身便是一个绑定行为,然后 MediaQueryData
又和键盘状况有联系,所以:键盘的弹出或许会导致运用 MediaQuery.of(context)
的当地触发 rebui嵌套分类汇总的操作步骤ld,举个比方:
如下代码所示,咱们在 MyHomePage
里运用了 MediaQuery.of(context).size
并打印输出,然flutter开发的app有哪些后跳转到 EditPage
页面,弹出键盘 ,这flutter框架时候会产生什么情况?
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("######### MyHomePage ${MediaQuery.of(context).size}");
return Scaffold(
body: Container(
alignment: Alignment.center,
child: InkWell(
onTap: () {
Navigator.of(context).push(CupertinoPageRoute(builder: (context) {
return EditPage();
}));
},
child: new Text(
"Click",
style: TextStyle(fontSize: 50),
),
),
),
);
}
}
class EditPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: new Text("ControllerDemoPage"),
),
extendBody: true,
body: Column(
children: [
new Spacer(),
new Container(
margin: EdgeInsets.all(10),
child: new Center(
child: new TextField(),
),
),
new Spacer(),
],
),
);
}
}
如下图 lo缓存视频变成本地视频g 所示 , 能够看到在键盘弹起来的进程,由于 bottom 产生改动缓存,所以 MediaQueryD嵌套查询ata
产生了改动APP,从而导致上一级的 MyHomePage
尽管不行见,可是在键盘弹起的进程里也被不断 build 。
试想一下,假如你在每个页面开端的方位都是嵌套是什么意思用了
MediaQuery.of(context)
,然后打appstore开了 5 个页面,这时候你在第 5 个页面弹出键盘时,也触发安全教育平台登录入口了前面 4 个页面 rebuild,天然而然或许就会呈现卡顿。
那么假如我不在 MyHomePage
的 build 办法直接运用 MediaQue缓存文件夹名称ry.of(contex嵌套查询t)
,那在 EditPage
里弹出键盘是不是就不会导致上一级的 MyHomePage
触发 build ?
答案是必定的,没有了
MediaQuery.of(context).size
之后,MyapplicationHomePage
就不会由于EditPage
里的键盘弹出而导致 rebuild。
所以小技巧一:要慎重在 Scaffold
之外运用 MediaQuery.of(context)
,或许你现在会觉得古怪什么是 S嵌套是什么意思caffold
之外,没事后面持续解释。
那到这儿有人或许就要说了:咱们经过 MediaQuery.of(context)
获取到的 MediaQueryData
,不便是对应在 MaterialApp
里的 MediaQue嵌套查询sql语句ry
吗?那它产生改动,不应该都会触发fluttershy下面的 child 都 rebuild 吗?
这其实和页面路由有联系,也便是咱们常说的
PageRoute
的实现。
如下图所示,由于嵌套结构的原因,事实上弹出键盘的确会导致 MaterialApp
下的 child 都触发 rebuild ,由于设计上 MediaQuery
便是在 Navigator
上面,所以弹出安全教育手抄报键盘天然也就触发 Navigator
的 rebuild。
那正常情况下 Navigator
都触发 rebuild 了,为什么页面不会都被 rebuild 呢?
这就和路由目flutter面试题标的基类 ModalRoute
有联系,由于在它的内部会经过一个 _modalScopeflutteredCache
参数把 Widget
缓存起来,正如注释所说:
缓存区域不随帧变化,以便得到最小化的构建。
举个比方,如下代码所示:
- 首先界说了一个
TextGlobal
,在 build 办法里输出"######## TextGlobal"
- 然后在
MyHomePage
里界说一个大apple局的TextGlobal globalText = TextGl安全教育平台作业登录obal();
- 接着在
My安全教育日HomePage
里添加 3 个 globalText - 最后点击
FloatingActionBu嵌套分类汇总怎么做tton
触发setState(() {});
class TextGlobal extends StatelessWidget {
const TextGlobal({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
print("######## TextGlobal");
return Container(
child: new Text(
"测试",
style: new TextStyle(fontSize: 40, color: Colors.redAccent),
textAlign: TextAlign.center,
),
);
}
}
class MyHomePage extends StatefulWidget {
final String? title;
MyHomePage({Key? key, this.title}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextGlobal globalText = TextGlobal();
@override
Widget build(BuildContext context) {
print("######## MyHomePage");
return Scaffold(
appBar: AppBar(),
body: new Container(
alignment: Alignment.center,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
globalText,
globalText,
globalText,
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {});
},
),
);
}
}
那么有趣的来了,如下图 log 所示,"######## TextGlobal"
除了在一开端构建时有输出之外,剩余 setState(() {});
的时候都没有在触发,也便是没有 rebuild ,这其实便是上面 ModalRoute
的相似行为:弹出键盘导致了 MediaQuery
触发 Navigator
履行 rebuild,可是 rebuild 到了 ModalRoute
就不往下影响。
其实这个行为也体现在了 Scaffol安全教育日d
里,假如你去看嵌套函数 Scaffolflutter开发的app有哪些d
的源码,你就会发现 Scaffold
里flutter是什么意思大量运用了 MediaQuery.of(context)
。
比方上面的代码,假如你给 MyHomePage
的 ScafFlutterfold
装备一个 3333 的 ValueKey
,那么在 EditPage
弹出键盘时,其实 MyHomePage
的 Scaffold
是会触发 rebuild ,可是由于其flutter菜鸟教程运用的是 wi缓存清理dget.body
,所以并不会导致 body
内目标重构。
假如是
MyHomePage
假如 rebuild ,就会对 build 办法里所有的装备的new
目标进行 rebuild;可是假如只是MyHomePage
里的Scaffold
内部触发了 rebuild ,是不会导致MyHomePage
里的 body 参数安全生产法对应的 child 履行 rebuild 。
是不是太笼统?举个简略的比方,如下代码所示:
- 咱们界说了一个
LikeScaffold
控件,在控件内经过缓存是什么意思widget.body
传递目标 - 在
Li缓存视频变成本地视频keScaffoldflutter面试题
内部咱们运用了MediaQuery.of(context).viewInsets.bottom
,模仿Scaffold
里运用MediaQuery
- 在
MyHo缓存的视频在哪mePage
里运用LikeScaffold
,并给LikeappstoreScaffold
的 body 装备一个Builder
,输出"############ HomePage Builder Text "
用于调查 - 跳到
EditPage
页面打开键盘
class LikeScaffold extends StatefulWidget {
final Widget body;
const LikeScaffold({Key? key, required this.body}) : super(key: key);
@override
State<LikeScaffold> createState() => _LikeScaffoldState();
}
class _LikeScaffoldState extends State<LikeScaffold> {
@override
Widget build(BuildContext context) {
print("####### LikeScaffold build ${MediaQuery.of(context).viewInsets.bottom}");
return Material(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [widget.body],
),
);
}
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
var routeLists = routers.keys.toList();
return new LikeScaffold(
body: Builder(
builder: (_) {
print("############ HomePage Builder Text ");
return InkWell(
onTap: () {
Navigator.of(context).push(CupertinoPageRoute(builder: (context) {
return EditPage();
}));
},
child: Text(
"FFFFFFF",
style: TextStyle(fontSize: 50),
),
);
},
),
);
}
}
能够看到,最开端 "####### LikeScaffold build 0.0
和 ############ HomePage Builder Text
都正常履行,然后在键盘弹出之安全教育平台登录后,"####### LikeScaffold build
跟从键盘动画不断输出 bottom
的 巨细,可是 "############ HomePage Builder Text ")
没有输出,由于它是 widget.body
实例。
所以经过这个最小比方,能够看到尽管 Scaffold
里大量运缓存文件夹名称用 MediaQuery.of(context)
,可是影响范围是约束在 Scaffoldflutter有必要学吗
内部。
接着咱们持续看修改这个比方,假如在 LikeScaffold缓存是什么意思
上嵌套多一个 Scaffold
,那输出结果会是apple怎么样?
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
var routeLists = routers.keys.toList();
///多加了个 Scaffold
return Scaffold(
body: new LikeScaffold(
body: Builder(
),
),
);
}
答案是 LikeScaffold
内的 "####### LikeScaffo嵌套虚拟化ld build
也不会由于键盘的弹起而输出,也便是: Lik嵌套查询sql语句eScaflutteringffold
尽管运用了 MediaQuery.of(context)
,可是它不再由于键盘的弹起而导致 rebuild 。
由于此刻 LikeScaffold
是 Scaffold
的 child ,所以在 Lik嵌套if函数eScaffold
内经过 MediaQuery.of(context)
指向的,其实是 Sc缓存文件夹名称affold
内部经过处理的 MediaQueryData
。
在
Scaffold
内部有很多相似的处理,例如body
里会依据是否有Appbar
和BottomNavigationBar
来决议是否移除该区域内的 paddingTappleop 和 paddingBottom 。
所以,看到这儿有没有想到什么?为什么时不时经过 MediaQuery.of(context缓存)
获取的 pappointmentadding ,有的 top 为 0 ,有的不为 0 ,原因就在于你获取的 context 来自哪里。
举个比方,如下代码所示, ScaffoldChildPage
作为 Scaffold
的 child ,咱们分别在 MyHomePage
和 ScaffoldChildPag安全教育平台登录e
里打印 MediaQuery.of(context).padding
:
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("MyHomePage MediaQuery padding: ${MediaQuery.of(context).padding}");
return Scaffold(
appBar: AppBar(
title: new Text(""),
),
extendBody: true,
body: Column(
children: [
new Spacer(),
ScaffoldChildPage(),
new Spacer(),
],
),
);
}
}
class ScaffoldChildPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("ScaffoldChildPage MediaQuery padding: ${MediaQuery.of(context).padding}");
return Container();
}
}
如下图所示,能够看到,由于此刻 MyHomePage
有 Appbar
,所以 ScaffoldChildPage
里获取到 paddingTop 是 0 ,由于此刻 ScaffoldC缓存英文hildPage
获取到的 Medi安全期计算器aQueryData
现已被 MyHomePage
里的 Scaffold
改写了。
假如此flutter有必要学吗刻你给 MyHomePage
增加了 BottomNavigationBar
,能够看到 Scaffol嵌套查询sql语句dChilappeardPage
的 bottom 会从原本的 34 变成 90 。
到这儿能够看到 MedappointmentiaQuery.of
里的 context 目标很重要:
- 假如页面
MediaQuery.of
用的是S缓存的视频在哪caffold
外的cont缓存视频合并ext
,获取到的是顶层的M嵌套函数ediaQueryData
,那么弹出键盘时就会导致页面 rebuild -
MediaQue缓存清理ry.of
用的是Scaffold
内的context
,那么获取到的是Scaffold
关于区域内的MediaQueryData嵌套
,比方前面介绍过的 body ,一安全教育日起缓存视频合并获取安全教育平台登录到的MediaQueryData
也会由于Scaffold
的装备不同而产生改动
所以,如下动图所示,其实部分人会在 push 对应路由当地,经过嵌套 MediaQuery
来做一些阻拦处理,比方设置文本不行缩放,可是其实这样appear会导致键盘在弹出和收起时,触发各个页面不断 r安全教育手抄报ebuild ,比方在 Page 2安全生产法 弹出键盘的进程,Page 1 也在不断 rebuild。
所以,假如需求做一些大局阻拦,引荐经过 useInheritedMediaQuery
这种方法来做大局处理fluttering。
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance!.window).copyWith(boldText: false),
child: MaterialApp(
useInheritedMediaQuery: true,
),
);
所以最后做个总结,本篇首要理清了:
-
MediaQueryData
里viewInsets
padding
viewPadding
的差异 -
MediaQuery
和键盘状况的联系 -
MediaQu缓存视频合并ery.of
运用不同 context 对功能的影响 - 经过
Scflutter开发的app有哪些affold
内的context
获取到的MediaQueryData
受到Scaffold
的影响
那么,嵌套查询假如看完本篇你appointment还有什么疑惑,欢迎留言谈论沟通。