天天看點

Flutter StatelessWidget,StatefulWidget和它們的生命周期函數StatelessWidget 和 StatefulWidget

這個轉自我自己的有道雲 想看圖檔去那裡

文檔:Day3_2 StatelessWidget 和 StatefulWi…

連結:http://note.youdao.com/noteshare?id=71abe63a08ed806e44911f636b452b44&sub=AC2B27FCC2AA41FE86AB93B15475B063

StatelessWidget 和 StatefulWidget

  • StatelessWidget 的案例
  • StatefulWidget 的案例
  • StatefulWidget的生命周期

1. StatelessWidget

我們經過之前的練習知道了, 這個東西是無狀态的Widget, 他的資料是不能變的

StatelessWidget練習

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-rzraKNvW-1583548791492)(4DAC89A36141444591BDE15A137B9CC5)]

我們從頭寫起

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

           

然後把架構搭好

  • 我們發現直接寫extends StatelessWidget速度太慢, 是以這裡可以使用一個快速的寫法
  • 我們寫出stl 然後回車就可以快速打出 對應的繼承代碼
  • 但是我們要使用material的樣式而且要展示home界面是以需要這樣嵌套

Scaffold 這個東西就像Android中的Activity 是一樣的

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StatelessWidget練習")
      ),
      body: HYHomeList(),
    );
//    注意這裡和java 那些東西不一樣需要加分号
  }
}

class HYHomeList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ;
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-IQuy2NTk-1583548791494)(D1785F6E751A4EA58D078E59808124EE)]

然後我們觀察這個項目的結構

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-hHjZXyaw-1583548791496)(93E9474DD60046048B3C898ACE94CA6F)]

我們先寫出架構

  • 因為我們這裡是從上往下放多個是以這裡是Column
  • 如果是放多個就是children, 放一個就是child
import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StatelessWidget練習")
      ),
      body: HYHomeList(),
    );
//    注意這裡和java 那些東西不一樣需要加分号
  }
}

class HYHomeList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text("hahah"),
        Text("hahha"),
        Text("hahaha")
      ],
    );
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-TTcdlZnL-1583548791496)(4187A953B1F14A46AFDD2E12ECFEA8C6)]

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-HIOeRhl7-1583548791497)(93E9474DD60046048B3C898ACE94CA6F)]

這個裡面也是一個Column

HYHomeListItem 的設計

  • 因為這個很明顯, 他需要顯示不同的内容
  • 我們flutter是一個面向對象的語言

是以我們的Widget可以設定成要傳參數的那種

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StatelessWidget練習")
      ),
      body: HYHomeList(),
    );
//    注意這裡和java 那些東西不一樣需要加分号
  }
}

class HYHomeList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-04-22/b0201606065bcdad3159cd02c9199a01.jpg"),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-07-27/c4d6ea4d8c51e0aa3c750aed13913a1b.jpg"),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/celve/2019-03-04/55ce1f75dac4b12a4aae1ec691b83400.jpg")
      ],
    );
  }
}


class HYHomeListItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeListItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text(title),
        Text(desc),
        Image.network(imageURL)
      ],
    );
  }
}

           

是以這個裡面也是item Widget

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-vG7qnv4P-1583548791497)(70C3F731820246E7ADC926AA5AE6A1C2)]

但是下面報錯了

A RenderFlex overflowed by 285 pixels on the bottom.

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-8uKNOSol-1583548791498)(2C12B763EB14423AA00843860FD9CEC9)]

意思是說超出了, 我們的Widget超出了螢幕的範圍

我們換用ListView代替最外面的Column, 讓最外面可以滾動這個問題就可以解決了

import 'package:flutter/material.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StatelessWidget練習")
      ),
      body: HYHomeList(),
    );
//    注意這裡和java 那些東西不一樣需要加分号
  }
}

class HYHomeList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-04-22/b0201606065bcdad3159cd02c9199a01.jpg"),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-07-27/c4d6ea4d8c51e0aa3c750aed13913a1b.jpg"),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/celve/2019-03-04/55ce1f75dac4b12a4aae1ec691b83400.jpg")
      ],
    );
  }
}


class HYHomeListItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeListItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Text(title),
        Text(desc),
        Image.network(imageURL)
      ],
    );
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-K1Vlbhnt-1583548791499)(0D7949F3C6174E9CA7E2DAFCA985B5A3)]

但是如果我們不希望你居中

  • 這個時候我們可以設定itemWidget中的Column交叉軸屬性

但是這個不是一般的做法

class HYHomeListItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeListItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: <Widget>[
        Text(title),
        Text(desc),
        Image.network(imageURL)
      ],
    );
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-6Kp0vHDe-1583548791499)(CEB3740EDFFA40BFBC904B41995AF078)]

這樣我們就可以居左居右了

  • 但是如果你想title居左 desc居右 那我們就需要在裡面再嵌入Row讓裡面的東西可以自行設定他的居左居右
  • 注意這個Row是占據一整行的

這個就是一般做法

class HYHomeListItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeListItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Text(title),
          ],
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Text(desc),
          ],
        ),
        Image.network(imageURL)
      ],
    );
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-5E7i9OH3-1583548791500)(42F45FFB5A8F4AAF97CBB0D7B7292AFC)]

調整樣式

class HYHomeListItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeListItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Text(title, style: TextStyle(fontSize: 30, color: Colors.red),),
          ],
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Text(desc, style: TextStyle(fontSize: 20, color: Colors.blue)),
          ],
        ),
        Image.network(imageURL)
      ],
    );
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-OSjgRgGM-1583548791500)(53C41C5F1A61452CA6364E5469558B1E)]

設定外邊距

然後我如果希望這些Widget間有些間距的話我們可以使用SizedBox

  • 一般來說如果我們使用的是html那種東西的話, 我們因該是設定類似于margin-top 之類的東西
  • 但是在flutterz中我們沒有這種東西
  • 是以我們為了撐高度使用的是SizedBox(height: number)
  • 如果想要左右邊距的話我們使用Alignment就可以了

因為flutter中萬物皆Widget是以margin 這種也是屬于Widget的(當然有些是屬于widget的屬性的)

class HYHomeList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-04-22/b0201606065bcdad3159cd02c9199a01.jpg"),
        SizedBox(height: 10),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-07-27/c4d6ea4d8c51e0aa3c750aed13913a1b.jpg"),
        SizedBox(height: 10),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/celve/2019-03-04/55ce1f75dac4b12a4aae1ec691b83400.jpg")
      ],
    );
  }
}


class HYHomeListItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeListItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Text(title, style: TextStyle(fontSize: 30, color: Colors.red),),
          ],
        ),
        SizedBox(height: 8),
        Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Text(desc, style: TextStyle(fontSize: 20, color: Colors.blue)),
          ],
        ),
        SizedBox(height: 8),
        Image.network(imageURL)
      ],
    );
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-NhdSW4xF-1583548791501)(F5D7CDE5D2364A4DB592BAC917707F2F)]

設定内邊距

如果我們覺得這個東西挨着邊框不好看

那麼我們可以設定他的padding

這個東西padding: EdgeInsets.all(8) 直接在ListView上面加

class HYHomeList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(8),
      children: <Widget>[
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-04-22/b0201606065bcdad3159cd02c9199a01.jpg"),
        SizedBox(height: 10),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-07-27/c4d6ea4d8c51e0aa3c750aed13913a1b.jpg"),
        SizedBox(height: 10),
        HYHomeListItem("title", "desc", "https://www.lianaiyx.com/d/file/celve/2019-03-04/55ce1f75dac4b12a4aae1ec691b83400.jpg")
      ],
    );
  }
}
           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-d1KU53zu-1583548791502)(435875AA074941298D05F5D119E78BE3)]

設定邊框

然後我們覺得這個還是有一個邊框比較好

這個東西因該加在item上面但是item沒有這個屬性

  • 邊框這個東西需要Container來設定, 其實就是一個普通的Widget
  • 因為Column是裝多個widget給他設定border肯定不合适
  • 這裡我們使用alt + enter 加上container包裹的快捷鍵
  • 然後設定Container的border
class HYHomeListItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  HYHomeListItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(8),
      decoration: BoxDecoration(
        border: Border.all(
          width: 5,
          color: Colors.red
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              Text(title, style: TextStyle(fontSize: 30, color: Colors.red),),
            ],
          ),
          SizedBox(height: 8),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              Text(desc, style: TextStyle(fontSize: 20, color: Colors.blue)),
            ],
          ),
          SizedBox(height: 8),
          Image.network(imageURL)
        ],
      ),
    );
  }
}
           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-ifyRVLwW-1583548791502)(7C13287C51C046158B01D00FF54A0653)]

StatalessWidget完整代碼

import 'package:flutter/material.dart';

main() => runApp(MyApp());

//直接寫效率太低了
//我們直接敲stl就會生成對應的代碼
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: HYHomePage(),
//      這個就是一啟動顯示的頁面
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text("商品清單")
      ),
      body: HYHomeContent(),
    );
  }
}

class HYHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    現在隻是想回顧一下這個StatelessWidget
    return ListView(
//      要放多個 是以是children 不是 child
      children: <Widget>[
//        我們因該在裡面放商品資料
//      The specific RenderFlex in question is: RenderFlex#af73a relayoutBoundary=up1 OVERFLOWING
//      這個是操作布局邊界 希望讓它變成可滾動的區域
        HYHomeProductItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-04-22/b0201606065bcdad3159cd02c9199a01.jpg"),
        SizedBox(height: 6),
        HYHomeProductItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-07-27/c4d6ea4d8c51e0aa3c750aed13913a1b.jpg"),
        SizedBox(height: 6),
        HYHomeProductItem("title", "desc", "https://www.lianaiyx.com/d/file/GalGame/2019-03-05/6c815fb726391c117d1d6b0a126fa643.jpg"),
      ],
    );
  }
}

//我們使用同一個Widget但是我們希望展示的東西是不一樣的
//
class HYHomeProductItem extends StatelessWidget {
  final String title;
  final String desc;
  final String imageURL;

  final style1 = TextStyle(fontSize: 25, color: Colors.orange);
  final style2 = TextStyle(fontSize: 20, color: Colors.green);
  HYHomeProductItem(this.title, this.desc, this.imageURL);

  @override
  Widget build(BuildContext context) {

//    我們現在想要設計一個邊框
//    如果想要包裹一個widget我們可以使用alt + enter
    return Container(
//      如果我們希望和裡面的東西有一個内邊距
      padding: EdgeInsets.all(12),
//      decoration這個東西是一個抽象類
      decoration: BoxDecoration(
//        ctrl + alt + B 就可以看到它的實作類
          border: Border.all(
//          這個東西就是設定邊框的寬度
              width: 5,
//          設定邊框顔色
              color: Colors.black12
//            這個12是一個透明度的意思
          )
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.end,
//        但是實際上我們因該通過 交叉軸而是在裡面嵌套 Row然後在裡面
        children: <Widget>[
//          我們想要居右
//          , textAlign: TextAlign.right 這個沒有用 文本是包裹内容的是以居左居右
//        這個東西是Column是以我們設定的是它的交叉軸
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              Text(title, style: style1, textAlign: TextAlign.right),
            ],
          ),
//        flutter沒有margin-top之類的東西是以
          SizedBox(height: 8),
          Row(
            children: <Widget>[
              Text(desc, style: style2),
            ],
          ),
//        這個八個像素 但是是和裝置有關系
//      後面
//        如果是想要左右邊距離的話Alignmen就可以了
          SizedBox(height: 8),
          Row(
            children: <Widget>[
              Image.network(imageURL)
            ],
          )
        ],
      ),
    );
  }
}

           

2. StatefulWidget的使用示例

  • 為什麼flutter在設計的時候StatefulWidget的build方法放在State中
    1. build出來的Widget是需要以來State中的變量(狀态)
    2. flutter運作過程中Widget是不斷銷毀建立的 Element-Render-Object
  • 當時我們狀态發生改變的時候, 并不希望建立一個新的State

是以我們呢才會将StatefulWidget和State實作類分離

執行個體

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-ZVuEUKM7-1583548791502)(1FF62F62A746427D8D1194B6D6714C51)]

  • 首先我們搭建出平台
import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return HYHomePage();
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomeContent(),
    );
  }
}

class HYHomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("statefulWidget示例"),
      ),
      body: Text("test")
    );
  }
}

           

如果我們要做計數器很明顯我們需要具有狀态的Widget

是以就需要用StatefulWidget

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("statefulWidget示例"),
      ),
      body: Text("test")
    );
  }
}

class HYHomeContent extends StatefulWidget {
  @override
  _HYHomeContentState createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

           

然後就是結構和StatelessWidget不同是的我們的渲染的架構是在繼承StatefulWidget, 因該是寫在State裡面

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("statefulWidget示例"),
      ),
      body: Center(child:HYHomeContent())
    );
  }
}

class HYHomeContent extends StatefulWidget {
  @override
  _HYHomeContentState createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              color: Colors.red,
              child: Text("+", style: TextStyle(color: Colors.white)),
              onPressed: () {

              },
            ),
            RaisedButton(
              color: Colors.green,
              child: Text("-", style: TextStyle(color: Colors.white)),
              onPressed: () {

              },
            )
          ],
        ),
        Text("counter: $_counter")
      ],
    );
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-TshD7TJE-1583548791503)(236D8204F87B4A6283A0CD5579F74810)]

但是我們直接改變變量的值還是不行的

  • 我們必須要調用setState重新整理
  • 這個東西就是調用重新整理頁面的意思, 是以你如果把變量的改變寫在前面寫在後面都是一樣的
  • 再強調一遍私有屬性是會加_ 加了隻有這個變量就會隻屬于這個 庫
  • 這個注意 這裡如果要分離State的作為一個新的widget則是是需要将我們的函數作為閉包傳過去 然後在那邊調用
import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage(),
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("statefulWidget示例"),
      ),
      body: Center(child:HYHomeContent())
    );
  }
}

class HYHomeContent extends StatefulWidget {
  @override
  _HYHomeContentState createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              color: Colors.red,
              child: Text("+", style: TextStyle(color: Colors.white)),
              onPressed: () {
                ++_counter;
                setState(() {

                });
              },
            ),
            RaisedButton(
              color: Colors.green,
              child: Text("-", style: TextStyle(color: Colors.white)),
              onPressed: () {
                setState(() {
                  --_counter;
                });
              },
            )
          ],
        ),
        Text("counter: $_counter")
      ],
    );
  }
}
           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-fvcLFTYQ-1583548791503)(6C3739A610094A2F8631AC662BDBC587)]

我們看到源碼裡面其實它也是在setState裡面調了傳進去的參數的

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-aTQ4ALCN-1583548791504)(04E6A1BEBEDD4139A8BCC168D705E8AD)]

指向StatefulWidget的指針

還有如果你想要再StatefulWidget中傳參數 然後再後面展示

可以再傳的方式 也可以用state指向StatefulWidget對象的指針來實作這個功能

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("statefulWidget示例"),
      ),
      body: Center(child:HYHomeContent("傳遞的參數"))
    );
  }
}

class HYHomeContent extends StatefulWidget {
  final String message;

  HYHomeContent(this.message);

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

class _HYHomeContentState extends State<HYHomeContent> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              color: Colors.red,
              child: Text("+", style: TextStyle(color: Colors.white)),
              onPressed: () {
                ++_counter;
                setState(() {

                });
              },
            ),
            RaisedButton(
              color: Colors.green,
              child: Text("-", style: TextStyle(color: Colors.white)),
              onPressed: () {
                setState(() {
                  --_counter;
                });
              },
            )
          ],
        ),
        Text("counter: $_counter ${widget.message}")
      ],
    );
  }
}
           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-tKOKjZkB-1583548791505)(79250287C7004999B1970578F4AACF0D)]

3. StatfulWidget和StatelessWidget的生命周期函數

  • 生命周期函數也被稱為“hook” “鈎子函數”
  • 其主要功能就是在程式運作到指定位置時進行回調
  • 生命周期函數的功能
    1. 初始化一些資料, 變量, 狀态
    2. 發送網絡請求
    3. 監聽元件中的事件 controller 添加監聽事件(滾動事件)
    4. 管理記憶體: 一些定時器-controller手動進行銷毀

StatelessWidget的生命周期函數很簡單

主要就是StatelessWidget構造函數和build函數

其實就是沒有專門的生命周期函數, 因為它沒有狀态, 是以它也簡單的多

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: HYHomeContent()
    );
  }
}

class HYHomeContent extends StatelessWidget {

  HYHomeContent() {
    print("HYHomeContent 構造函數執行");
  }

  @override
  Widget build(BuildContext context) {
    print("HYHomeConten build函數執行");
    return Text("content");
  }
}


           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-XxPaQwMg-1583548791505)(530E35C0AA264130B6EC3915933ECDE0)]

StatefulWidget的生命周期函數

重要

先建立一個簡單的StatefulWidget

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-ip2UwgJp-1583548791505)(5CF4FCB23BB740C7A6855B909120D2CB)]

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StatefulWidget的生命周期函數")
      ),
      body: HYHomeContent()
    );
  }
}

class HYHomeContent extends StatefulWidget {
  @override
  _HYHomeContentState createState() => _HYHomeContentState();
}

class _HYHomeContentState extends State<HYHomeContent> {
  int _counter = 0;

//  如果我們想要拆分這個東西因該怎麼辦
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Text("+"),
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
        ),
        Text("counter: $_counter")
      ],
    );
  }
}

           

然後将生命周期函數寫上去

  1. StatefulWidget子類的構造方法
  2. StatefulWidget子類的createState方法
  3. State子類的構造方法
  4. State子類的initState方法
  5. State子類的build方法
  6. State子類的dispose方法
import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StatefulWidget的生命周期函數")
      ),
      body: HYHomeContent()
    );
  }
}

class HYHomeContent extends StatefulWidget {
  HYHomeContent() {
    print("1. 調用HYHomeContent的構造函數");
  }

  @override
  _HYHomeContentState createState() {
    print("2. 調用HYhomeContent的createState方法");
    return _HYHomeContentState();
  }
}

class _HYHomeContentState extends State<HYHomeContent> {
  int _counter = 0;

  _HYHomeContentState() {
    print("3. 調用_HYHomeContentState的構造函數");
  }

  @override
  void initState() {
    // TODO: implement initState
    print("4. 調用_HYHomeContentState的initState方法");
//    下面這個必須寫
    super.initState();
  }

//  如果我們想要拆分這個東西因該怎麼辦
  @override
  Widget build(BuildContext context) {
    print("5.  調用_HYHomeContentState的build方法");
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Text("+"),
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
        ),
        Text("counter: $_counter")
      ],
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    print("6. 調用_HYHomeContentState的dispose方法");
    super.dispose();
  }
}

           

後面這個反複調用是Android Studio 的bug, vscode就沒有

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-mqD1bPq3-1583548791506)(B0C29EE84CBF40A4B8090FBCF3943420)]

  • 在我們點選+以後 會不停的調用build
  • 這個過程其實也就是不停重建Widget過程
  • 這個也是驗證了Widget是不停的銷毀和建立的

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-1dshXOXz-1583548791506)(F25C1882E1ED4A8DB29BD6B0A6EFAEA8)]

還有一些其他的生命周期函數那些不是很常用但是還是需要知道

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HYHomePage()
    );
  }
}

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StatefulWidget的生命周期函數")
      ),
      body: HYHomeContent()
    );
  }
}

class HYHomeContent extends StatefulWidget {
  HYHomeContent() {
    print("1. 調用HYHomeContent的構造函數");
  }

  @override
  _HYHomeContentState createState() {
    print("2. 調用HYhomeContent的createState方法");
    return _HYHomeContentState();
  }
}

class _HYHomeContentState extends State<HYHomeContent> {
  int _counter = 0;

  _HYHomeContentState() {
    print("3. 調用_HYHomeContentState的構造函數");
  }

  @override
  void initState() {
    // TODO: implement initState
    print("4. 調用_HYHomeContentState的initState方法");
//    下面這個必須寫
    super.initState();
  }

  @override
  void didUpdateWidget(HYHomeContent oldWidget) {
    // TODO: implement didUpdateWidget
    print("調用——HYHomeContentState的didUpdateWidget方法");
    super.didUpdateWidget(oldWidget);
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    //    這個數據依賴一些東西的時候 依賴的東西改變了就會調用
//    就是裏面的東西 假如依賴了 InheritedWidget的message 假如這個改變了
//  就會調用didChangeDependecies
    print("調用_HYHomeContenState的didChangeDepancies");
    super.didChangeDependencies();
  }

//  如果我們想要拆分這個東西因該怎麼辦
  @override
  Widget build(BuildContext context) {
    print("5.  調用_HYHomeContentState的build方法");
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Text("+"),
          onPressed: () {
            setState(() {
              _counter++;
            });
          },
        ),
        Text("counter: $_counter")
      ],
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    print("6. 調用_HYHomeContentState的dispose方法");
    super.dispose();
  }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-WtZcALT6-1583548791507)(B51E30A28D63489492042D24E7DF0BA4)]