Flutter一切皆widget但是不要将所有东西放入一个widget
本文主要介紹Flutter一切皆widget但是不要將所有東西放入一個widget
作為 Flutter 開發人員,我相信您在您的開發生活中至少聽說過這句流行的句子:“**一切都是widget”。這是 Flutter 的口頭禪,它揭示了這個非常好的 SDK 的內在力量!
當我們在widgets目錄中,我們可以看到很多小部件,如Padding,Align,SizedBox,等。我們通過組合它們來創建其他小部件,我發現這種方法可擴展、強大且易于理解。
但是當我閱讀 一些我在互聯網上找到的或由新采用者編寫的源代碼時,有一件讓我震驚的事情:擁有大量build**`**方法的趨勢,實例化很多小部件!我發現這很難閱讀、理解和維護。
作為軟件開發人員,我們必須記住,軟件的真實生活從第一次發布給用戶開始。該軟件的源代碼將由其他人(包括您未來的您)閱讀和維護,這就是為什么保持我們的代碼簡單、易于閱讀和理解非常重要。
“小部件中的一切”的示例可以在Flutter 文檔本身中找到。本教程的目標是展示如何構建此布局:
最終代碼達到了它的目的:展示如何簡單地創建上述布局。正如我們所見,甚至還有一些變量和方法可以為布局的各個部分提供語義。這是一個很好的觀點,因為它使代碼更容易理解。
import 'package:flutter/material.dart';void main() {runApp(MyApp()); }class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {Widget titleSection = Container(padding: const EdgeInsets.all(32),child: Row(children: [Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Container(padding: const EdgeInsets.only(bottom: 8),child: Text('Oeschinen Lake Campground',style: TextStyle(fontWeight: FontWeight.bold,),),),Text('Kandersteg, Switzerland',style: TextStyle(color: Colors.grey[500],),),],),),Icon(Icons.star,color: Colors.red[500],),Text('41'),],),);Color color = Theme.of(context).primaryColor;Widget buttonSection = Container(child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [_buildButtonColumn(color, Icons.call, 'CALL'),_buildButtonColumn(color, Icons.near_me, 'ROUTE'),_buildButtonColumn(color, Icons.share, 'SHARE'),],),);Widget textSection = Container(padding: const EdgeInsets.all(32),child: Text('Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese ''Alps. Situated 1,578 meters above sea level, it is one of the ''larger Alpine Lakes. A gondola ride from Kandersteg, followed by a ''half-hour walk through pastures and pine forest, leads you to the ''lake, which warms to 20 degrees Celsius in the summer. Activities ''enjoyed here include rowing, and riding the summer toboggan run.',softWrap: true,),);return MaterialApp(title: 'Flutter layout demo',home: Scaffold(appBar: AppBar(title: Text('Flutter layout demo'),),body: ListView(children: [Image.asset('images/lake.jpg',width: 600,height: 240,fit: BoxFit.cover,),titleSection,buttonSection,textSection,],),),);}Column _buildButtonColumn(Color color, IconData icon, String label) {return Column(mainAxisSize: MainAxisSize.min,mainAxisAlignment: MainAxisAlignment.center,children: [Icon(icon, color: color),Container(margin: const EdgeInsets.only(top: 8),child: Text(label,style: TextStyle(fontSize: 12,fontWeight: FontWeight.w400,color: color,),),),],);} }事實上,情況可能更糟。這是我不喜歡的這段代碼的典型多合一小部件版本:。
import 'package:flutter/material.dart';void main() {runApp(MyApp()); }class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {Color color = Theme.of(context).primaryColor;return MaterialApp(title: 'Flutter layout demo',home: Scaffold(appBar: AppBar(title: Text('Flutter layout demo'),),body: ListView(children: [Image.asset('images/lake.jpg',width: 600,height: 240,fit: BoxFit.cover,),Container(padding: const EdgeInsets.all(32),child: Row(children: [Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Container(padding: const EdgeInsets.only(bottom: 8),child: Text('Oeschinen Lake Campground',style: TextStyle(fontWeight: FontWeight.bold,),),),Text('Kandersteg, Switzerland',style: TextStyle(color: Colors.grey[500],),),],),),Icon(Icons.star,color: Colors.red[500],),Text('41'),],),),Container(child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [Column(mainAxisSize: MainAxisSize.min,mainAxisAlignment: MainAxisAlignment.center,children: [Icon(Icons.call, color: color),Container(margin: const EdgeInsets.only(top: 8),child: Text('CALL',style: TextStyle(fontSize: 12,fontWeight: FontWeight.w400,color: color,),),),],),Column(mainAxisSize: MainAxisSize.min,mainAxisAlignment: MainAxisAlignment.center,children: [Icon(Icons.near_me, color: color),Container(margin: const EdgeInsets.only(top: 8),child: Text('ROUTE',style: TextStyle(fontSize: 12,fontWeight: FontWeight.w400,color: color,),),),],),Column(mainAxisSize: MainAxisSize.min,mainAxisAlignment: MainAxisAlignment.center,children: [Icon(Icons.share, color: color),Container(margin: const EdgeInsets.only(top: 8),child: Text('SHARE',style: TextStyle(fontSize: 12,fontWeight: FontWeight.w400,color: color,),),),],),],),),Container(padding: const EdgeInsets.all(32),child: Text('Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese ''Alps. Situated 1,578 meters above sea level, it is one of the ''larger Alpine Lakes. A gondola ride from Kandersteg, followed by a ''half-hour walk through pastures and pine forest, leads you to the ''lake, which warms to 20 degrees Celsius in the summer. Activities ''enjoyed here include rowing, and riding the summer toboggan run.',softWrap: true,),),],),),);} }在第二個版本中,我們有一個大build方法的小部件,它很難閱讀、理解和維護。
現在讓我們看看我將如何重寫它:
import 'package:flutter/material.dart';void main() {runApp(MyApp()); }class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter layout demo',home: const HomePage(),);} }class HomePage extends StatelessWidget {const HomePage({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Flutter layout demo'),),body: ListView(children: [const _Header(),const _SubHeader(),const _Buttons(),const _Description(),],),);} }class _Header extends StatelessWidget {const _Header({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Image.asset('images/lake.jpg',width: 600,height: 240,fit: BoxFit.cover,);} }class _SubHeader extends StatelessWidget {const _SubHeader({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Container(padding: const EdgeInsets.all(32),child: Row(children: [Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [const _Title(),const _SubTitle(),],),),const _Likes(),],),);} }class _Title extends StatelessWidget {const _Title({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Container(padding: const EdgeInsets.only(bottom: 8),child: Text('Oeschinen Lake Campground',style: TextStyle(fontWeight: FontWeight.bold,),),);} }class _SubTitle extends StatelessWidget {const _SubTitle({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Text('Kandersteg, Switzerland',style: TextStyle(color: Colors.grey[500],),);} }class _Likes extends StatelessWidget {const _Likes({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Row(children: <Widget>[Icon(Icons.star,color: Colors.red[500],),Text('41'),],);} }class _Buttons extends StatelessWidget {const _Buttons({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Container(child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: [const _Button(icon: Icons.call, text: 'CALL'),const _Button(icon: Icons.share, text: 'ROUTE'),const _Button(icon: Icons.share, text: 'SHARE'),],),);} }class _Button extends StatelessWidget {const _Button({Key key,@required this.icon,@required this.text,}) : assert(icon != null),assert(text != null),super(key: key);final IconData icon;final String text;@overrideWidget build(BuildContext context) {Color color = Theme.of(context).primaryColor;return Column(mainAxisSize: MainAxisSize.min,mainAxisAlignment: MainAxisAlignment.center,children: [Icon(icon, color: color),Container(margin: const EdgeInsets.only(top: 8),child: Text(text,style: TextStyle(fontSize: 12,fontWeight: FontWeight.w400,color: color,),),),],);} }class _Description extends StatelessWidget {const _Description({Key key,}) : super(key: key);@overrideWidget build(BuildContext context) {return Container(padding: const EdgeInsets.all(32),child: Text('Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese ''Alps. Situated 1,578 meters above sea level, it is one of the ''larger Alpine Lakes. A gondola ride from Kandersteg, followed by a ''half-hour walk through pastures and pine forest, leads you to the ''lake, which warms to 20 degrees Celsius in the summer. Activities ''enjoyed here include rowing, and riding the summer toboggan run.',softWrap: true,),);} }你不覺得這更易讀嗎?
🤔 有什么好處?
我理解為什么教程不經常這樣做:它需要更多行(在我的示例中為 100 行),人們可能想知道為什么我們要創建這么多其他小部件。由于教程旨在專注于一個概念,因此這樣編寫它們可能會適得其反。但結果是,新采用者可能傾向于在他們的build方法中放置一個大的小部件樹。
讓我們看看為布局的每個部分都有一個獨特的小部件有什么好處:
可讀性
我們為布局的每個語義部分創建一個小部件。因此,每個小部件都有一個較小的build方法。它更易于閱讀,因為您無需滾動即可到達小部件的末尾。
可理解性
每個小部件都有一個與其角色匹配的名稱,這稱為語義命名。通過這樣做,當我們閱讀代碼時,更容易在我們的腦海中映射代碼的哪一部分與我們在應用程序上看到的內容相匹配。我在這里看到了可理解性方面的兩個改進:
\1. 當我們閱讀其他地方引用的此類小部件時,我們幾乎知道它的作用,而無需查看其實現。
2.在閱讀帶有語義命名的小部件的構建方法之前,我們已經對其內容有一個大致的了解。
可維護性
如果您必須更換一個組件或更改一個部件,它只會在一個地方,與其他小部件的其余部分分開。多虧了這種做法,它更不容易出錯,因為每個小部件的角色都得到了很好的定義。在您的應用程序甚至另一個應用程序中的另一個頁面中共享布局的一部分也將更加容易。
Performances
前面的所有原因應該足以讓您采用這種方式來創建 Flutter 應用程序,但是這樣做還有一個好處:我們提高了應用程序的性能,因為每個小部件都可以與其他小部件分開重建(事實并非如此如果我們使用方法來分隔我們的布局部分)。例如,假設我們必須在單擊它時增加紅星旁邊的數字。在這個版本中,我們可以制作_Likes一個StatefulWidget并處理這里的增量。當用戶點擊星星時,只有_Likes小部件會被重建。在第一個版本中,MyApp如果我們將其設為StatefulWidget.
Flutter 文檔中也解釋了這種最佳實踐:
當setState()在狀態上調用時,所有后代小部件都將重建。因此,將setState()調用本地化到 UI 實際需要更改的子樹部分。如果更改包含在樹的一小部分,請避免在樹的高處調用 setState()。
另一個優點是能夠const更頻繁地使用關鍵字。然后可以緩存和重新使用小部件。正如Flutter 文檔所述:
重用小部件比創建新的(但配置相同的)小部件要高效得多。
?? 如何提高工作效率?
如您所見,通過為布局的每個語義部分創建一個小部件,我們編寫了更多代碼。我們可以在 Visual Studio Code 中使用Dart擴展提供的stless和stful片段,
為了我自己的需要,我創建了新的片段,稱為sless和sful,這樣我的工作效率比以往任何時候都高。如果您希望在 Visual Studio Code 中使用它們,則必須遵循此文檔并添加以下內容:
{"Flutter stateless widget": {"scope": "dart","prefix": "sless","description": "Insert a StatelessWidget","body": ["class $1 extends StatelessWidget {"," const $1({"," Key key,"," }) : super(key: key);",""," @override"," Widget build(BuildContext context) {"," return Container("," $2"," );"," }","}"]},"Flutter stateful widget": {"scope": "dart","prefix": "sful","description": "Insert a StatefulWidget","body": ["class $1 extends StatefulWidget {"," const $1({"," Key key,"," }) : super(key: key);",""," @override"," _$1State createState() => _$1State();","}","","class _$1State extends State<$1> {"," @override"," Widget build(BuildContext context) {"," return Container("," $2"," );"," }","}"]}, }📕 結論
我相信這是編寫 Flutter 應用程序的好方法,我希望你也相信。如果不是這樣,我對你的意見很感興趣😉!
從現在開始,記住這句話:“Everything’s a widget but don’t put everything in one widget!”。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Flutter一切皆widget但是不要将所有东西放入一个widget的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每个开发人员都应该知道的 15 个 In
- 下一篇: 信息系统项目管理师项目变更管理