從零開始的Flutter之旅: StatelessWidget

此次要展現的是什麼是Flutter的Widget,即小部件;以及如何在Flutter中使用StatelessWidget,即無狀態小部件。html

至於Flutter,通俗的講是開發者能夠通一套簡單的代碼來同時構建Android與IOS應用程序。git

特性

小部件是Flutter應用程序的基本構建模塊,每個都是不可變的聲明,也是用戶界面的一部分。例如button,text,color以及佈局所用到的padding等等。github

下面咱們來看flutter_github中的一個實例。web

圈選中的item只有兩個信息,頭像與名稱。爲了不代碼的重複使用,將其抽離成一個獨立的widget,具體代碼以下bash

class FollowersItemView extends StatelessWidget {
  final GestureTapCallback tapCallback;
  final String avatarUrl;
  final String name;
 
  const FollowersItemView(
      {Key key, this.avatarUrl, this.name, this.tapCallback})
      : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 15.0),
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: tapCallback,
        child: Column(
          children: <Widget>[
            Row(
              children: <Widget>[
                FadeInImage.assetNetwork(
                  placeholder: 'images/app_welcome.png',
                  image: avatarUrl,
                  width: 80.0,
                  height: 80.0,
                ),
                Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(left: 15.0),
                    child: Text(
                      name,
                      overflow: TextOverflow.ellipsis,
                      maxLines: 1,
                      style: TextStyle(
                        color: Colors.grey[600],
                        fontSize: 20.0,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                )
              ],
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 15.0),
              child: Divider(
                thickness: 1.0,
                color: colorEAEAEA,
                height: 1.0,
                endIndent: 0.0,
              ),
            ),
          ],
        ),
      ),
    );
  }
}
複製代碼

它繼承於StatelessWidget,StatelessWidget的特性是無狀態,數據不可變化。這個性質正好符合咱們將要抽離的部件。抽離的部件須要作頭像與名稱的展現,沒有任何形式上的交互變化。惟一的一個交互也是點擊,但它並無涉及數據的改變。因此在代碼中將這些數據定義成final類型。本質就如Text部件,並無如輸入文本或者帶有動畫的部件同樣隨着時間內部屬性會有所變化。微信

既然沒有任何變化,那麼咱們也能夠將其構造函數定義爲const類型。網絡

有了上面的部件抽離,咱們就能夠直接在ListView中使用該無狀態部件架構

@override
  Widget createContentWidget() {
    return RefreshIndicator(
      onRefresh: vm.handlerRefresh,
      child: Scrollbar(
        child: ListView.builder(
            padding: EdgeInsets.only(top: 15.0),
            itemCount: vm.list?.length ?? 0,
            itemBuilder: (BuildContext context, int index) {
              final item = vm.list[index];
              return FollowersItemView(
                avatarUrl: item.avatar_url,
                name: item.login,
                tapCallback: () {
                  Navigator.push(context, MaterialPageRoute(builder: (_) {
                    return WebViewPage(title: item.login, url: item.html_url);
                  }));
                },
              );
            }),
      ),
    );
  }
複製代碼

在ListView中引用FollowItemView,並傳入不變的數據便可。app

呈現原理

如今StatelessWidget的使用你們都會了,那它是如何調用的呢?框架

下面咱們來看下它的呈現原理。

正如開頭所說的將小部件做爲Flutter應用構建的基礎,在Flutter中咱們將小部件的構建稱做爲Widget Tree,即小部件樹。它就像是應用程序的藍圖,咱們將藍圖建立好,而後內部會經過藍圖去建立對應顯示在屏幕上的element元素。它包含了藍圖上對應的小部件的配置信息。因此對應的還有一個Element Tree,即元素樹。

每個StatelWidget都有一個StatelessElement,內部會經過createElement()方法進行建立其實例

@override
  StatelessElement createElement() => StatelessElement(this);
複製代碼

同時在StatelessElement中會經過buid()方法來獲取StalessWidget中所構建的藍圖Widget,並將元素顯示到屏幕上。

Widget Tree與Element Tree之間的交互以下

FollowerItemView中的StatelessElement會調用build方法來獲取它是否有子部件,若是有的話對應的子部件也會建立它們本身的Element,並把它安裝到元素樹上。

因此咱們的程序有兩顆對應的樹,其中一顆表明屏幕上顯示的內容Element;另外一顆樹表明其展現的藍圖Widget,它們由許多的小部件組成。

而咱們開發人員所作的就是將這些不一樣的小部件構建成咱們所須要的應用程序。

最後,咱們再來了解下最初的安裝入口。

void main() {
  runApp(GithubApp());
}
複製代碼

在咱們的main文件中,有一個main函數,其中調用了runApp方法,傳入的是GithubApp。咱們再來看下GithubApp是什麼?

class GithubApp extends StatefulWidget {
  @override
  _GithubAppState createState() {
    return _GithubAppState();
  }
}
 
class _GithubAppState extends State<GithubApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Github',
      theme: ThemeData.light(),
      initialRoute: welcomeRoute.routeName,
      routes: {
        welcomeRoute.routeName: (BuildContext context) => WelcomePage(),
        loginRoute.routeName: (BuildContext context) => LoginPage(),
        homeRoute.routeName: (BuildContext context) => HomePage(),
        repositoryRoute.routeName: (BuildContext context) => RepositoryPage(),
        followersRoute.routeName: (BuildContext context) =>
            FollowersPage(followersRoute.pageType),
        followingRoute.routeName: (BuildContext context) =>
            FollowersPage(followingRoute.pageType),
        webViewRoute.routeName: (BuildContext context) => WebViewPage(title: '',),
      },
    );
  }
}
複製代碼

發現沒它其實也是一個Widget,正如文章開頭所說的,Flutter是由各個Widget組成。main是程序的入口,而其中的runApp中的Widget是整個程序掛載的起點。它會建立成一個具備與屏幕寬高一致的根元素,並把它裝載到屏幕中。

因此在Flutter中一直都是經過建立Element,而後調用build方法來獲取其後續的子Widget,最終構建成咱們所看到的程序。

文中的代碼都是來自於flutter_github,這是一個基於Flutter的Github客戶端同時支持Android與IOS,支持帳戶密碼與認證登錄。使用dart語言進行開發,項目架構是基於Model/State/ViewModel的MSVM;使用Navigator進行頁面的跳轉;網絡框架使用了dio。項目正在持續更新中,感興趣的能夠關注一下。

固然若是你想了解Android原生,相信flutter_github的純Android版本AwesomeGithub是一個不錯的選擇。

下期預告

從零開始的Flutter之旅: StatefulWidget

若是你喜歡個人文章模式,或者對我接下來的文章感興趣,建議您關注個人微信公衆號:【Android補給站】

或者掃描下方二維碼,與我創建有效的溝通,同時更快更準的收到個人更新推送。

相關文章
相關標籤/搜索