Flutter-基礎(chǔ)組件一

在Flutter中,Widget是一切的基礎(chǔ)火惊,作為響應(yīng)式渲染,屬于MVVM的實(shí)現(xiàn)機(jī)制奔垦,通過修改數(shù)據(jù),再用setState設(shè)置數(shù)據(jù)尸疆,F(xiàn)lutter會(huì)自動(dòng)通過綁定的數(shù)據(jù)更新Widget椿猎。

1.StatelessWidget 和 StatefulWidget

在平時(shí),用的最多就是StatelessWidget和StatefulWidget這兩種Widget寿弱,StatelessWidget表示無狀態(tài)的犯眠,StatefulWidget表示有狀態(tài)的。
在Flutter中每個(gè)頁面都是一幀症革,無狀態(tài)就是保持在那一幀筐咧,總而言之就是不能跟用戶交互,當(dāng)有狀態(tài)的Widget當(dāng)數(shù)據(jù)更新時(shí),其實(shí)是繪制了新的Widget量蕊,也就是UI發(fā)生了變化铺罢,只是State實(shí)現(xiàn)了跨幀數(shù)據(jù)同步保存。

1)StatelessWidget
源碼:

abstract class StatelessWidget extends Widget {
  // 初始化子類的[key]残炮。這個(gè)key類是Widget韭赘、Element、SemanticsNode的唯一標(biāo)識符
  // 是用來控制Widget數(shù)中替換Widget的時(shí)候使用的势就。
  const StatelessWidget({ Key key }) : super(key: key);

 // 創(chuàng)建一個(gè)[StatelessElement]來管理這個(gè)小部件在樹中的位置
  @override
  StatelessElement createElement() => StatelessElement(this);

  // 描述這部件呈現(xiàn)用戶界面的部分
  @protected
  Widget build(BuildContext context);
}

函數(shù):Widget build(BuildContext context):

作用:用于描述當(dāng)前widget所代表的UI

調(diào)用時(shí)機(jī):

  • Widget首次插入樹中時(shí)調(diào)用
  • 父節(jié)點(diǎn)更改了配置
  • 它所依賴的InheritedWidget改變時(shí)
import 'package:flutter/material.dart';
//使用`flutter/material.dart` 目的是使用Matrial風(fēng)格的小控件
void main(){
   // 類比iOS入口main函數(shù)
  //運(yùn)行程序 
  runApp(MyApp('你是豬嗎'));
}
//繼承無狀態(tài)的StatelessWidget 使程序自身變?yōu)閃iget
class MyApp extends StatelessWidget{

  //要顯示的內(nèi)容
  final String text;

  //數(shù)據(jù)內(nèi)容可以通過構(gòu)造方法傳遞進(jìn)來
  MyApp(this.text);

  //重寫build方法 返回你需要的控件
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      //紅色背景
      color: Colors.red,
      //高度 現(xiàn)在沒用 會(huì)撐滿整個(gè)屏幕
      height: 200,
      //寬度 運(yùn)行效果會(huì)撐滿整個(gè)屏幕
      width: 200,
      //內(nèi)容居中
      alignment: Alignment.center,
      //Text控件
      child: new Text(
        text ?? "hello",
         textDirection: TextDirection.ltr,//文本展示方向泉瞻,從左向右。需要加上這句不然報(bào)錯(cuò)
      ),

    );
  }
}

2)StatefulWidget
有狀態(tài)的控件,狀態(tài)是在創(chuàng)建控件可以同步讀取信息苞冯,并且在控件的生命周期內(nèi)可以改變袖牙,當(dāng)控件狀態(tài)發(fā)生改變時(shí)使用State.setState來及時(shí)更新。

源碼:

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
 
  @override
  StatefulElement createElement() => StatefulElement(this);

  @protected
  State createState();
}


函數(shù):State createState()

作用:在Widget樹中給定的位置上舅锄,創(chuàng)建此可變狀態(tài)的小部件贼陶,子類應(yīng)該重寫此方法返回新建的關(guān)聯(lián)子類的實(shí)例。

調(diào)用時(shí)機(jī):當(dāng)調(diào)用一個(gè)StatefulWidget巧娱,框架就會(huì)調(diào)用createState這個(gè)方法碉怔,當(dāng)一個(gè)StatefulWidget從Widget樹中移除,再次插入樹中禁添,那么會(huì)再次調(diào)用createState來創(chuàng)建一個(gè)新的State對象撮胧,這樣做簡化了State對象的生命周期。

StatefulWidget本身是不可變的老翘,它可變的狀態(tài)存儲在與之關(guān)聯(lián)的State對象中芹啥。

State對象生命周期;

  • 初始化時(shí)期 initState
  • 更新時(shí)期 didChangeDependencies 铺峭、build 墓怀、didUpdateWidget
  • 銷毀時(shí)期 deactivate 和 dispose

initState:類似于iOS的viewDidLoad(),在這個(gè)方法中通常會(huì)做一些初始化工作。

didChangeDependencies:這個(gè)方法在兩種情況下會(huì)調(diào)用卫键,當(dāng)調(diào)用initState方法時(shí)調(diào)用傀履;當(dāng)從其他對象依賴的數(shù)據(jù)發(fā)生變化時(shí)調(diào)用,如InheritedWidget莉炉。

didUpdateWidget:這是一個(gè)不常用到的生命周期方法钓账,當(dāng)父組件需要重新繪制時(shí)才會(huì)調(diào)用。

build: 這是一個(gè)必須實(shí)現(xiàn)的方法絮宁,在這里實(shí)現(xiàn)你要顯示的頁面內(nèi)容梆暮,它會(huì)在didChangeDependencies方法之后立即調(diào)用,另外當(dāng)調(diào)用setState()后也會(huì)再次調(diào)用該build方法绍昂。

deactivate:很少使用啦粹,在組件被移除時(shí)候調(diào)用偿荷,在dispose之前調(diào)用。

dispose:常用唠椭,組件被銷毀時(shí)候調(diào)用跳纳。通常在該方法中執(zhí)行一些資源的釋放工作。



import 'package:flutter/material.dart';
//使用`flutter/material.dart` 目的是使用Matrial風(fēng)格的小控件
import 'dart:async';//記得導(dǎo)庫
void main(){
  //運(yùn)行程序
  runApp(StateWidget());
}

//繼承StatefulWidget
class StateWidget extends StatefulWidget{
  
   @override
   State createState(){
     return _StateWidget();
   }
}

//控件繼承State
class _StateWidget extends State<StateWidget>{
  int number = 0;
  String text;
  //構(gòu)造函數(shù)
  _StateWidget(this.text);

  @override
  void initState(){
    //初始化泪蔫,這個(gè)函數(shù)在控件的生命周期內(nèi)調(diào)用一次
    super.initState();
    print("進(jìn)入initState");
    //3秒后改變text的內(nèi)容
    new Future.delayed(const Duration(seconds: 3),(){
      setState(() {
        number++;
        text = "已經(jīng)改變數(shù)值棒旗,數(shù)值現(xiàn)在是$number";
      });

    });
  }

  @override
  void dispose(){
    //銷毀
    super.dispose();
    print('銷毀');
  }

  @override
  void didChangeDependencies(){
    //在initState之后調(diào)
     super.didChangeDependencies();
     print('進(jìn)入didChange');
  }

  //重寫build方法
  @override
  Widget build(BuildContext context){
    return Container(
      //紅色背景
      color: Colors.red,
      //內(nèi)容居中
      alignment: Alignment.center,
      //Text控件
      child: new Text(
        //Dart語法中 ?? 表示如果text為空,就會(huì)返回??號的內(nèi)容
        text ?? "沒改變數(shù)值",
        textDirection: TextDirection.ltr,//需要加上這句不然報(bào) RichText widgets require a Directionality widget ancestor.
      ),

    );
  }
}


3)StatelessWidget和StatefulWidget使用選擇撩荣,以及性能問題铣揉。

  • 樹根上盡量不用狀態(tài)控件,因?yàn)槿绻麛?shù)據(jù)有變化樹根每次都更新餐曹,那就是整棵樹都要重建逛拱,把狀態(tài)用在樹葉上,這樣更新的時(shí)候只會(huì)更新自己台猴。
  • 減少build方法所創(chuàng)建的節(jié)點(diǎn)數(shù)量和控件數(shù)量朽合。
  • 利用緩存,如果子樹中不更改饱狂,將子樹中緩存起來曹步,每次使用其子樹時(shí)重新使用它适室,學(xué)會(huì)重用思想月弛。
  • 盡可能使用const修飾控件吻谋。
2.主體結(jié)構(gòu)組件

1)MaterialApp和CupertinoApp

Flutter 中包含兩套風(fēng)格的組件逗栽,分別是 Material 和 Cupertino 。
MaterialApp 是由 Google 推出的 Material Design設(shè)計(jì)風(fēng)格的組件埠况。
Cupertino 是 iOS風(fēng)格的組件夭坪,命名都帶 Cupertino 前綴将宪,比如 CupertinoSlider 雏婶、CupertinoDatePicker等物赶。

二者屬性基本相同,用法相似留晚,CupertinoApp有些會(huì)帶Cupertino前綴酵紫,常用屬性介紹;

  • title : 這個(gè)和啟動(dòng)圖標(biāo)名字是不一樣的倔丈,在任務(wù)管理窗口中所顯示的應(yīng)用名字憨闰。
  • theme : 應(yīng)用各種 UI 所使用的主題顏色。
  • color : 應(yīng)用的主要顏色值(primary color)需五,也就是安卓任務(wù)管理窗口中所顯示的應(yīng)用顏色。
  • home : 應(yīng)用默認(rèn)所顯示的界面Widget轧坎。
  • routes : 定義應(yīng)用中頁面跳轉(zhuǎn)規(guī)則宏邮,當(dāng)使用 Navigator.pushNamed 來路由的時(shí)候,會(huì)在 routes 查找路由名字,然后使用 對應(yīng)的 WidgetBuilder 來構(gòu)造一個(gè)帶有頁面切換動(dòng)畫的 MaterialPageRoute蜜氨。
  • initialRoute :第一個(gè)顯示的路由名字械筛,默認(rèn)值為 Window.defaultRouteName。
  • onGenerateRoute:生成路由的回調(diào)函數(shù)飒炎,當(dāng)導(dǎo)航的命名路由的時(shí)候埋哟,會(huì)使用這個(gè)來生成界面。
  • onLocaleChanged:當(dāng)系統(tǒng)修改語言的時(shí)候郎汪,會(huì)觸發(fā)這個(gè)回調(diào)赤赊。
  • navigatorObservers :應(yīng)用 Navigator 的監(jiān)聽器。
  • debugShowMaterialGrid:是否顯示紙墨設(shè)計(jì)基礎(chǔ)布局網(wǎng)格煞赢,用來調(diào)試 UI 的工具抛计。
  • showPerformanceOverlay :顯示性能標(biāo)簽。
  • checkerboardRasterCacheImages 照筑、showSemanticsDebugger吹截、debugShowCheckedModeBanner 各種調(diào)試開關(guān)。

2)Scaffold

Scaffold 翻譯過來就是腳手架的意思凝危,一個(gè)提供 Material Design 設(shè)計(jì)中基本布局的 widget波俄。

常用屬性介紹:

  • appBar:導(dǎo)航欄。
  • body: 用于顯示當(dāng)前界面主要內(nèi)容的Widget蛾默。
  • floatingActionButton:一個(gè)懸浮在body上的按鈕懦铺,默認(rèn)顯示在右下角。
  • floatingActionButtonLocation:用于設(shè)置floatingActionButton顯示的位置趴生。
  • floatingActionButtonAnimator:floatingActionButton移動(dòng)到一個(gè)新的位置時(shí)的動(dòng)畫阀趴。
  • persistentFooterButtons:多狀態(tài)按鈕。
  • drawer:左側(cè)的抽屜菜單苍匆。
  • endDrawer:右'側(cè)的抽屜菜單刘急。
  • bottomNavigationBar:底部導(dǎo)航欄,同iOS的tabbar。
  • bottomSheet:顯示在底部的工具欄浸踩。
  • backgroundColor:內(nèi)容背景顏色叔汁。
  • resizeToAvoidBottomPadding :控制界面內(nèi)容 body 是否重新布局來避免底部被覆蓋,比如當(dāng)鍵盤顯示的時(shí)候检碗,重新布局避免被鍵盤蓋住內(nèi)容据块。

3)AppBar
應(yīng)用導(dǎo)航欄,相當(dāng)于iOS中的navigationBar折剃。

常用屬性介紹:

  • leading:設(shè)置導(dǎo)航欄返回的組件另假,相當(dāng)于iOS中的leftBarButtonItem。
  • title:導(dǎo)航欄標(biāo)題
  • actions:設(shè)置導(dǎo)航欄右邊的組件怕犁,一個(gè)Widget列表边篮,相當(dāng)于iOS中的rightBarButtonItems己莺。
  • bottom:一個(gè) AppBarBottomWidget 對象,通常是 TabBar戈轿。用來在 Toolbar 標(biāo)題下面顯示一個(gè) Tab 導(dǎo)航欄凌受。
  • backgroundColor: Appbar 的顏色,默認(rèn)值為 ThemeData.primaryColor思杯。
  • brightness:Appbar的亮度胜蛉,有白色和黑色兩種主題,默認(rèn)值為 ThemeData.primaryColorBrightness色乾。
  • iconTheme:Appbar上圖標(biāo)的顏色誊册、透明度、和尺寸信息杈湾。默認(rèn)值為 ThemeData.primaryIconTheme解虱。
  • textTheme:Appbar 上的文字樣式。
  • centerTitle:標(biāo)題是否居中顯示漆撞,默認(rèn)值根據(jù)不同的操作系統(tǒng)殴泰,顯示方式不一樣。

4)TabBar
標(biāo)簽導(dǎo)航組件浮驳,類似于新聞或者電商樣式中有關(guān)導(dǎo)航條下面有一個(gè)可以滾動(dòng)的一行按鈕悍汛,一般和AppBar連用,設(shè)置AppBar的bottom屬性至会。

常用屬性:

  • tabs:必須實(shí)現(xiàn)的离咐,設(shè)置需要展示的tabs,最少需要兩個(gè)奉件。
  • controller:標(biāo)簽選擇變化控制器宵蛀,TabController對象,默認(rèn)的DefaultTabController或者自定義TabController。
  • isScrollable:是否可滾動(dòng)县貌。
  • indicator:用于設(shè)定選中狀態(tài)下的展示樣式术陶。
  • indicatorColor:選中指示器的顏色。
  • indicatorWeight:選中下劃線的高度煤痕,值越大高度越高梧宫,默認(rèn)為2。
  • indicatorPadding:底部指示器的Padding摆碉。
  • indicatorSize:指示器大小計(jì)算方式塘匣,TabBarIndicatorSize.label跟文字等寬,TabBarIndicatorSize.tab跟每個(gè)tab等寬。
  • labelColor:選中l(wèi)abel顏色巷帝。
  • labelStyle:選中l(wèi)abel的Style忌卤。
  • labelPadding:每個(gè)label的padding值。
  • unselectedLabelColor:未選中l(wèi)abel顏色楞泼。
  • unselectedLabelStyle:未選中l(wèi)abel的Style埠巨。
  • onTap:點(diǎn)擊事件
class MyApp extends StatelessWidget{

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      title: 'demo',
      theme: ThemeData(
        //設(shè)置為藍(lán)色
          primarySwatch: Colors.blue
      ),
      home: MainWidget(),
    );
  }

}

class MainWidget extends StatelessWidget{

 final List <Widget> tabs = [
  Text('語文'),
  Text('數(shù)學(xué)' ),
  Text('英語'),
  Text('物理'),
  Text('化學(xué)'),
  Text('生物'),
  ];
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return DefaultTabController(
      length: tabs.length,
      child: Scaffold(
        backgroundColor: Colors.white,
        appBar: AppBar(
          title: Text('demo'),
          bottom: TabBar(tabs: tabs,
            onTap: (int index) {
              print('Selected......$index');
            },
            unselectedLabelColor: Colors.white,
            labelColor: Colors.black,
            labelStyle: TextStyle(fontSize: 20.0),
            isScrollable: true,
            indicatorColor: Colors.red,
            indicatorSize: TabBarIndicatorSize.label,
            indicatorWeight: 2.0,

          ),
        ),
        //選中哪個(gè)tab历谍,body就會(huì)顯示TabBarView中child屬性的widget
        body: TabBarView(children: tabs),
      ),
    );
  }
}

5)BottomNavigationBar

底部導(dǎo)航欄控件现拒,提供了頂級視圖之間的快速導(dǎo)航辣垒。
常用屬性:

  • currentIndex:當(dāng)前選item索引項(xiàng)。在onTap中控制當(dāng)前選中的item實(shí)現(xiàn)切換tab頁印蔬。
  • type:有兩個(gè)值勋桶,默認(rèn)值BottomNavigationBarType.shifting和BottomNavigationBarType.fixed,一般使用fixed。
  • backgroundColor:背景顏色侥猬。
  • selectedItemColor:選中item顏色例驹。
  • unselectedItemColor:未選中item顏色。
  • selectedFontSize:選中item文字大小退唠。
  • unselectedFontSize:未選中item文字大小鹃锈。
  • showUnselectedLabels:是否顯示未選中的Item的文字。
class _MainWidgetState extends State<MainWidget>{

  final List <Widget> tabs = [
    Text('語文'),
    Text('數(shù)學(xué)'),
    Text('英語'),
    Text('物理'),
  ];
  //底部Tab數(shù)據(jù)
  final Map bottomMap ={
    "首頁":Icon(Icons.home),
    "朋友圈":Icon(Icons.camera),
    "信息":Icon(Icons.message),
    "其他":Icon(Icons.devices_other),
  };

  List <BottomNavigationBarItem> tabItems(){
     var itemList = <BottomNavigationBarItem>[];
     bottomMap.forEach((key, value) {
       var item = BottomNavigationBarItem(
         title: Text(key),
         icon: value,
//         backgroundColor: Colors.blue
       );
       itemList.add(item);
     });

     return itemList;
  }

  var _index = 0;
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        title: Text('demo'),
      ),
      body: tabs[_index],
      bottomNavigationBar: BottomNavigationBar(
        items: tabItems(),
        backgroundColor: Colors.blue,
        selectedItemColor: Colors.white,
        unselectedItemColor: Colors.orange,
        type: BottomNavigationBarType.fixed,
        selectedFontSize: 12,
        currentIndex: _index,
        onTap: (idx){

          print("tab index $idx");
          setState(() {
            _index = idx;
          });
        },
      ),
    );
  }

}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞧预,一起剝皮案震驚了整個(gè)濱河市屎债,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌垢油,老刑警劉巖盆驹,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滩愁,居然都是意外死亡躯喇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門硝枉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廉丽,“玉大人,你說我怎么就攤上這事妻味≌梗” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵弧可,是天一觀的道長蔑匣。 經(jīng)常有香客問我,道長棕诵,這世上最難降的妖魔是什么裁良? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮校套,結(jié)果婚禮上价脾,老公的妹妹穿的比我還像新娘。我一直安慰自己笛匙,他們只是感情好侨把,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布犀变。 她就那樣靜靜地躺著,像睡著了一般秋柄。 火紅的嫁衣襯著肌膚如雪获枝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天骇笔,我揣著相機(jī)與錄音省店,去河邊找鬼。 笑死笨触,一個(gè)胖子當(dāng)著我的面吹牛懦傍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芦劣,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼粗俱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了虚吟?” 一聲冷哼從身側(cè)響起寸认,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎稍味,沒想到半個(gè)月后废麻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡模庐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年烛愧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掂碱。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怜姿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疼燥,到底是詐尸還是另有隱情沧卢,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布醉者,位于F島的核電站但狭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏撬即。R本人自食惡果不足惜立磁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剥槐。 院中可真熱鬧唱歧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沿后,卻和暖如春沿彭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背得运。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工膝蜈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人熔掺。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像非剃,于是被迫代替她去往敵國和親置逻。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345