当前位置:网站首页>Flutter tips: mediaquery and build optimization secrets you don't know
Flutter tips: mediaquery and build optimization secrets you don't know
2022-06-28 17:29:00 【Love cat de Xiaoguo】
The purpose of today's article is to complement your understanding of MediaQuery And the corresponding rebuild Basic cognition of mechanism , I believe this article will help you optimize performance and debugging bug It will help .
Flutter Everyone should be inseparable from MediaQuery , Such as through MediaQuery.of(context).size Get screen size , Or by MediaQuery.of(context).padding.top Get the status bar height , Use it casually MediaQuery.of(context) Is there any problem ?
First of all, we need to explain briefly , adopt MediaQuery.of Acquired MediaQueryData There are several very similar parameters in :
viewInsets: The size of the part completely obscured by the system user interface , Simply put, it is the keyboard heightpadding: Simply put, it's the status bar and the bottom security area , howeverbottomWill become... Because the keyboard pops up 0viewPadding: andpaddingequally , howeverbottomPart will not change
for instance , stay iOS On , As shown in the figure below , When the keyboard is ejected or not , You can see MediaQueryData Changes in some parameters in :
viewInsetsWhen the keyboard does not pop up 0, After the keyboard pops upbottombecome 336paddingBefore and after the keyboard pops up ,bottomfrom 34 Turned into 0viewPaddingThere is no change in the data before and after the keyboard pops up

You can see
MediaQueryDataThe data in the keyboard will change according to the keyboard state , Again becauseMediaQueryIt's aInheritedWidget, So we can passMediaQuery.of(context)Get the top-level sharedMediaQueryData.
So here comes the question ,InheritedWidget The update logic of , It is through registration context To bind , That is to say MediaQuery.of(context) Itself is a binding behavior , then MediaQueryData And it has something to do with the keyboard state , therefore : Ejecting the keyboard may cause the use of MediaQuery.of(context) Where to trigger rebuild, for instance :
As shown in the following code , We are MyHomePage Used in MediaQuery.of(context).size And print out , And then jump to EditPage page , Pop up keyboard , What happens at this time ?
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(),
],
),
);
}
}
Here's the picture log Shown , You can see the process of playing up on the keyboard , because bottom Change , therefore MediaQueryData It has changed , Thus leading to a higher level of MyHomePage Although not visible , But in the process of playing the keyboard, it is constantly build .

Just imagine , If you use at the beginning of each page
MediaQuery.of(context), Then it opens 5 A page , At this time you are in the 5 When a page pops up , Also triggered the front 4 A page rebuild, Naturally, there may be a Caton .
So if I'm not MyHomePage Of build Method directly use MediaQuery.of(context) , That's in EditPage If the keyboard pops up in the, it will not lead to a higher level MyHomePage Trigger build ?
The answer is yes , period
MediaQuery.of(context).sizeafter ,MyHomePageNot because ofEditPageThe keyboard pops up in the rebuild.
So trick One : Be careful Scaffold Use outside MediaQuery.of(context) , You may now wonder what it is Scaffold outside , It's OK. I'll explain later .
Then someone here may have to say : We go through MediaQuery.of(context) Acquired MediaQueryData , No, it corresponds to MaterialApp Inside MediaQuery Do you ? Then it changes , Should not all trigger the following child all rebuild Do you ?
This actually has something to do with page routing , That's what we often say
PageRouteThe implementation of the .
As shown in the figure below , Because of the nested structure , In fact, popping up the keyboard does lead to MaterialApp Under the child All trigger rebuild , Because the design MediaQuery Is in the Navigator above , So the pop-up keyboard will trigger Navigator Of rebuild.

Under normal circumstances Navigator All trigger rebuild 了 , Why don't all pages be rebuild Well ?
This is similar to the base class of the routing object ModalRoute It matters , Because inside it will pass a _modalScopeCache Parameter put Widget cached , As the note says :
The cache area does not change with the frame , To get a minimal build .

for instance , As shown in the following code :
- So we define one
TextGlobal, stay build Output in method"######## TextGlobal" - And then in
MyHomePageDefine a globalTextGlobal globalText = TextGlobal(); - And then
MyHomePageAdd in 3 individual globalText - Finally, click
FloatingActionButtonTriggersetState(() {});
class TextGlobal extends StatelessWidget {
const TextGlobal({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
print("######## TextGlobal");
return Container(
child: new Text(
" test ",
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(() {});
},
),
);
}
}
So interesting came , Here's the picture log Shown ,"######## TextGlobal" In addition to having output at the beginning of the build , be left over setState(() {}); It is not triggered at the time of , No rebuild , This is actually the top ModalRoute Similar behavior : Ejecting the keyboard causes MediaQuery Trigger Navigator perform rebuild, however rebuild here we are ModalRoute It doesn't affect .

In fact, this behavior is also reflected in Scaffold in , If you go to see Scaffold Source code , You'll find out Scaffold It's used a lot MediaQuery.of(context) .
Like the code above , If you give MyHomePage Of Scaffold To configure a 3333 Of ValueKey , So in EditPage When the keyboard pops up , Actually MyHomePage Of Scaffold Yes, it will trigger rebuild , But because it uses widget.body , So it doesn't lead to body Inner object refactoring .

If it is
MyHomePageIf rebuild , Would be right. build MethodnewObject to carry out rebuild; But if it's justMyHomePageInsideScaffoldInternally triggered rebuild , Will not lead toMyHomePageInside body Parameter corresponding child perform rebuild .
Is it too abstract ? A simple example , As shown in the following code :
- We define a
LikeScaffoldControl , Within the control, you can usewidget.bodyTransfer object - stay
LikeScaffoldInternally we useMediaQuery.of(context).viewInsets.bottom, imitationScaffoldUse inMediaQuery - stay
MyHomePageUse inLikeScaffold, And giveLikeScaffoldOf body To configure aBuilder, Output"############ HomePage Builder Text "Used to observe - Jump to the
EditPagePage open keyboard
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),
),
);
},
),
);
}
}
You can see , In the beginning "####### LikeScaffold build 0.0 and ############ HomePage Builder Text It's all working , Then after the keyboard pops up ,"####### LikeScaffold build Follow the keyboard animation and output continuously bottom Of size , however "############ HomePage Builder Text ") No output , Because it is widget.body example .

So through this minimal example , You can see that although Scaffold Use a lot of MediaQuery.of(context) , But the scope of influence is limited to Scaffold Inside .
Then we will continue to look at the modification of this example , If in LikeScaffold Nested one more Scaffold , What will the output result be ?
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
var routeLists = routers.keys.toList();
/// An extra Scaffold
return Scaffold(
body: new LikeScaffold(
body: Builder(
·····
),
),
);
}
The answer is LikeScaffold Internal "####### LikeScaffold build It will not output because the keyboard pops up , That is to say : LikeScaffold Although used MediaQuery.of(context) , But it is no longer caused by the bounce of the keyboard rebuild .
Because at this time LikeScaffold yes Scaffold Of child , So in LikeScaffold Pass inside MediaQuery.of(context) Point to the , It's actually Scaffold Internally processed MediaQueryData.

stay
ScaffoldThere are many similar processes inside , for examplebodyAccording to whether there isAppbarandBottomNavigationBarTo decide whether to remove the paddingTop and paddingBottom .
therefore , Did you think of anything here ? Why pass from time to time MediaQuery.of(context) Acquired padding , yes , we have top by 0 , Some are not for 0 , The reason is what you get context Where are from .
for instance , As shown in the following code , ScaffoldChildPage As Scaffold Of child , We are in MyHomePage and ScaffoldChildPage Internal printing 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();
}
}
As shown in the figure below , You can see , Because at this time MyHomePage Yes Appbar , therefore ScaffoldChildPage Get it from paddingTop yes 0 , Because at this time ScaffoldChildPage Acquired MediaQueryData Has been MyHomePage Inside Scaffold Rewrite the .

If you give MyHomePage Added BottomNavigationBar , You can see ScaffoldChildPage Of bottom From the original 34 become 90 .

Here you can see MediaQuery.of Inside context Objects matter :
- If the page
MediaQuery.ofIt's usingScaffoldExternalcontext, What you get is the top levelMediaQueryData, Then when the keyboard pops up, it will cause the page rebuild MediaQuery.ofIt's usingScaffoldInternalcontext, So what we get isScaffoldForMediaQueryData, For example, as mentioned above body , Obtained at the same timeMediaQueryDataBecause ofScaffoldThe configuration of is different
therefore , This is shown in the following GIF , In fact, some people will push Corresponding to the routing place , By nesting MediaQuery To do some interception processing , For example, set the text to be non scalable , But in fact, this will cause the keyboard to pop up and collapse , Trigger each page to keep rebuild , For example Page 2 The process of ejecting the keyboard ,Page 1 It's also going on rebuild.

therefore , If you need to do some global interception , Recommend to pass useInheritedMediaQuery This method is used to do global processing .
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance!.window).copyWith(boldText: false),
child: MaterialApp(
useInheritedMediaQuery: true,
),
);
So finally, make a summary , This chapter mainly clarifies :
MediaQueryDatainviewInsets\padding\viewPaddingThe difference betweenMediaQueryAnd keyboard stateMediaQuery.ofUse different context Impact on performance- adopt
ScaffoldInternalcontextAcquiredMediaQueryDatasufferScaffoldInfluence
that , If you have any doubts after reading this article , Welcome to comment and exchange .
边栏推荐
- Problems encountered in local deployment conflict: MySQL database code, isolation level and verification code are not displayed
- Potplayer play Baidu Cloud disk video
- "Jay bear" plummeted by 96.6%. Why is NFT with star goods cold?
- 彻底凉了!腾讯知名软件全线下架,网友一片唏嘘。。。
- 【TcaplusDB知识库】WebClient用户如何读取和修改数据
- The number of different integers in the character string of [3 questions (3) per day]
- Log management in MySQL log backup and recovery
- 几行代码就能实现复杂的 Excel 导入导出,这个工具类真心强大!
- AutoSAR 软件开发培训
- 【TcaplusDB知识库】批量复制游戏区
猜你喜欢

Anesthesia is not as simple as "one injection". Painless, safe and comfortable anesthesia is the first choice for patients

Solve the problem of sqoop error manager SqlManager: Generic SqlManager. listDatabases() not implemented

麻醉不止“打一针”那么简单,无痛、安全、舒适为患者首选

ICML 2022 | transferable imitation learning method based on decoupling gradient optimization

"Jay bear" plummeted by 96.6%. Why is NFT with star goods cold?

ZABBIX monitoring of traditional operation and maintenance (you get up early, I get up early, and we will get together sooner or later)

听说转行软件测试只能自学,培训机构是个坑?

老司机总结的12条 SQL 优化方案(非常实用)

Redis主从复制、哨兵、cluster集群原理+实验(好好等,会晚些,但会更好)

Redis persistence (les adolescents naviguent toujours rapidement, obstruent et ne tournent jamais)
随机推荐
MySQL中的日志管理 日志備份與恢複
win10用cmake3.22与vs2019编译curl库源码并调用
Home based efficient remote office | community essay solicitation
Potplayer plays Baidu cloud disk video
Summary and Thinking on interface test automation
logback 日志输出格式
IDC: Alibaba cloud ranks first in the market share of China's data governance platform in 2021
Squid proxy server application (I came from afar to make an appointment with you)
知乎热问:一个程序员的水平能差到什么程度?
Stackoverflow 2022 developer report: PostgreSQL surpasses MySQL!
Improving observability - business indicator monitoring practice
TDengine&nbsp;×英特尔 边缘洞见软件包 加速传统行业的数字化转型
AUTOSAR software development training
解决sqoop出现 ERROR manager.SqlManager: Generic SqlManager.listDatabases() not implemented
Practice of curve replacing CEPH in Netease cloud music
In rhel6.4, cacti+spine monitoring host is used to send email alarm
RHEL6.4中使用Cacti+Spine监控远程主机
Anesthesia is not as simple as "one injection". Painless, safe and comfortable anesthesia is the first choice for patients
区间乘积的因子数之和
Leetcode 6. Zigzag transformation (awesome, solved)