Flutter Web 網(wǎng)站之主頁(yè)框架搭建

往期

上期回顧

上期主要完成環(huán)境的搭建和部署,最終在jetpack.net.cn地址上呈現(xiàn),這期我們就開始搭建主頁(yè),構(gòu)建一個(gè)可以兼容三端(Android、Ios、Web)的主頁(yè)。

開始

在lib文件夾下創(chuàng)建home.dart文件,如圖



打開文件,輸入st出來(lái)的提示選擇第一個(gè),如圖


這樣就自動(dòng)生成一個(gè)完整的模版代碼,一個(gè)小小的技巧,請(qǐng)笑納。最后命名PageHome,這里簡(jiǎn)單說(shuō)下命名規(guī)則,只是建議,頁(yè)面以Page開頭,非頁(yè)面以Widget開頭,這樣在其他地方引用的時(shí)候容易尋找,提高查找效率。接下來(lái),我們就用一個(gè)兼容三端的組件來(lái)構(gòu)建主頁(yè),不賣關(guān)子,我們使用Material主題,因?yàn)槲沂茿ndroid開發(fā),更喜歡這個(gè)主題,我們?cè)谛略鼋M件的時(shí)候總感覺(jué)很麻煩,其實(shí)也有個(gè)小技巧,如圖


選第一個(gè)就可以生成一個(gè)包裹組件,繼續(xù)看圖


然后將widget改為Material。然后添加Padding,Scaffold組件如圖



Padding的用意很簡(jiǎn)單,加一個(gè)左右邊距,而在web,和手機(jī)上的邊距是不一樣的,不能固定死,我畫個(gè)圖展示展示下,如圖



所以使用ResponsiveWidget判斷是否是小屏幕,如果屏幕變小則使用小邊距來(lái)適配,這里注意是小屏幕,不是針對(duì)的Android或者蘋果手機(jī),要注意不能混淆理解,瀏覽器也可以縮小到手機(jī)屏幕大小對(duì)吧,要理解ResponsiveWidget請(qǐng)看前期博客:一個(gè)Flutter widget自動(dòng)適配不同UI到Web、Android
還有一個(gè)ScreenUtil,這個(gè)你可以理解為相當(dāng)于Android中的dp單位,他負(fù)責(zé)的就是等比適配,不會(huì)讓大小分辨率的屏幕看起來(lái)差距很大。這個(gè)工具有個(gè)初始化的過(guò)程

    ScreenUtil.instance = ScreenUtil.getInstance()..init(context);

而且初始化必須在MaterialApp包裹中,為什么呢?因?yàn)槲覀兪褂昧薓ediaQuery動(dòng)態(tài)獲取屏幕的寬高,詳細(xì)請(qǐng)看官方文檔https://api.flutter.dev/flutter/widgets/MediaQuery-class.html里面講的很清楚:
WidgetsApp and MaterialApp, which introduce a MediaQuery and keep it up to date with the current screen metrics as they change.
目前WidgetsApp和MaterialApp實(shí)現(xiàn)了MediaQuery的邏輯,所以你不在MaterialApp中初始化是會(huì)報(bào)錯(cuò)地,知道了吧。接下來(lái)看下實(shí)際運(yùn)行效果,我們將內(nèi)容設(shè)置成紅色來(lái)看,如圖


屏幕縮小后如圖


這就是我們要的效果,其實(shí)已經(jīng)有了兩個(gè)框架封裝的很完整,但前期我們?yōu)槭裁礇](méi)有選擇引用它們呢,而且他們實(shí)現(xiàn)的似乎更合理,請(qǐng)看他們的代碼風(fēng)格如圖


一個(gè)ScreenTypeLayout這個(gè)組件實(shí)現(xiàn)了四個(gè)屏幕的適配,框架引用:

  responsive_builder: ^0.1.5

我為什么沒(méi)有選擇直接使用呢?其實(shí)我們?cè)诿靼灼渲性砗蟠_實(shí)可以直接引用,但我還是建議自己寫一遍,通過(guò)自己的實(shí)現(xiàn),更清楚其中的道理不是嗎。前期的學(xué)習(xí)過(guò)程中,我們盡量的不去引用,選擇自己實(shí)現(xiàn),也是加快提高自己的一個(gè)辦法。多多學(xué)習(xí),多多練習(xí)。接下來(lái)我們實(shí)現(xiàn)Scaffold部分,Scaffold這個(gè)組件太好用了,先看下它原本的樣子


,它就像一個(gè)大的容器,幫住我們組織好了各個(gè)組件的位置,是對(duì)一個(gè)基礎(chǔ)UI的高度抽象。
簡(jiǎn)單分析下它的參數(shù)源碼


其實(shí)這里最主要的三個(gè)常用的部分appBar、body、floatingActionButton,正好是我們構(gòu)建一個(gè)UI的常用構(gòu)造,所以這個(gè)組件基本是我們使用頻率很高的一個(gè)組件,請(qǐng)認(rèn)真學(xué)習(xí)它,更詳細(xì)的學(xué)習(xí),請(qǐng)看https://api.flutter.dev/flutter/material/Scaffold-class.html,這里面有幾個(gè)例子,認(rèn)真學(xué)習(xí)哦,我們現(xiàn)在通過(guò)它,來(lái)構(gòu)建我們的主頁(yè)代碼,請(qǐng)看效果圖:


我們先構(gòu)建了AppBar的內(nèi)容,怎么實(shí)現(xiàn)的呢,請(qǐng)看代碼

 @override
  Widget build(BuildContext context) {
    ScreenUtil.instance = ScreenUtil.getInstance()..init(context);
    return Material(
        child: Padding(
      padding: EdgeInsets.symmetric(
          horizontal: !ResponsiveWidget.isSmallScreen(context)
              ? (ScreenUtil.getInstance().setWidth(108))
              : (ScreenUtil.getInstance().setWidth(6))),
      child: Scaffold(
        appBar: AppBar(
          title: _buildTitle(),  /// 左邊標(biāo)題
          backgroundColor: Color(0xFFf1f3f4),
          actions: !ResponsiveWidget.isSmallScreen(context)
              ? _buildActions(context)
              : null,  /// 右邊的menu菜單,這里在小屏幕不顯示。
        ),
        body: Center(child: Text('You have pressed the button $_count times.')),
      ),
    ));
  }

  Widget _buildTitle() {
    return RichText(
      text: TextSpan(
        // Note: Styles for TextSpans must be explicitly defined.
        // Child text spans will inherit styles from parent
        style: TextStyle(
          fontSize: 14.0,
          color: Colors.black,
        ),
        children: <TextSpan>[
          TextSpan(
            text: "Jetpack",
            style: TextStyles.logo,
          ),
          TextSpan(
            text: ".net.cn",
            style: TextStyles.logo.copyWith(
              color: Color(0xFF50AFC0),
            ),
          ),
        ],
      ),
    );
  }
  _buildActions(BuildContext context) {
      return <Widget>[
        MaterialButton(
          child: Text(
            'Home',
            style: TextStyles.menuItem,
          ),
          onPressed: () {
            if (ResponsiveWidget.isSmallScreen(context)) Navigator.pop(context);
          },
        ),
        MaterialButton(
          child: Text(
            'About',
            style: TextStyles.menuItem,
          ),
          onPressed: () {
            if (ResponsiveWidget.isSmallScreen(context)) Navigator.pop(context);
          },
        ),
      ];
  }

分別通過(guò)_buildTitle,_buildActions 實(shí)現(xiàn)左邊的標(biāo)題,右邊的菜單按鈕,里面有個(gè)細(xì)節(jié):


大屏幕的返回_buildActions,小屏幕直接隱藏,這里你可能有疑問(wèn),為什么不用drawer實(shí)現(xiàn)菜單?drawer適合小屏幕實(shí)現(xiàn),而大屏慕我們就要充分利用空間,盡可能的操作簡(jiǎn)單,一目了然。下面我們來(lái)實(shí)現(xiàn),小屏幕的drawer,請(qǐng)看代碼

///省略部分代碼
Scaffold(
        ///省略部分代碼
        drawer: _buildDrawer(context),
      ),

  _buildDrawer(BuildContext context) {
    return ResponsiveWidget.isSmallScreen(context)
        ? Drawer(
            child: ListView(
              padding: const EdgeInsets.all(20),
              children: _buildActions(context),
            ),
          )
        : null;
  }

給Scaffold添加一個(gè)drawer組件,這里用ListView把剛才的_buildActions組件再放進(jìn)來(lái),原來(lái)是以橫向展示,這次因?yàn)長(zhǎng)istView默認(rèn)是縱向,所以就是上下的展示方式,運(yùn)行項(xiàng)目后,如圖:


未展開的樣子,標(biāo)題右邊的菜單消失



展開的樣子,這就是我們要實(shí)現(xiàn)的小屏幕的樣子。也符合手機(jī)的使用習(xí)慣。



有沒(méi)有發(fā)現(xiàn)這個(gè)東東顯示看不清楚,接下來(lái)我們改造它,可我沒(méi)做過(guò),我怎么查呢?我這里分享我的經(jīng)驗(yàn),首先你要明白這里的關(guān)鍵字是什么,當(dāng)我鼠標(biāo)停留在上面的時(shí)候提示如圖

是一個(gè)navigation menu,所以我會(huì)在google里搜索,flutter scaffold drawer navigation menu,這么幾個(gè)關(guān)鍵字,然后搜到的如圖

,第一個(gè)是官方文檔如何添加,第二個(gè)是custom drawer,自定義的,有可能講到了如何修改,所以我就點(diǎn)進(jìn)去尋找



看到?jīng)],還是很好找的哈,然后copy過(guò)來(lái)代碼,發(fā)現(xiàn)它用的圖不對(duì),我們修改下,如圖,這樣是不是看著舒服了。


接下來(lái)就是給Scaffold的body填充內(nèi)容了,先看實(shí)現(xiàn)的效果
Home頁(yè)面黃色



About頁(yè)藍(lán)色



點(diǎn)擊切換,具體實(shí)現(xiàn)請(qǐng)看下面代碼
       int _selectedDrawerIndex = 0;
       ///定義一個(gè)坐標(biāo)值
      /// 添加動(dòng)態(tài)的body _getDrawerItemWidget
      child: Scaffold(
        body: _getDrawerItemWidget(_selectedDrawerIndex),
      ),
      /// 省略部分代碼
      /// 根據(jù)一個(gè)index值,來(lái)確定加載哪個(gè)頁(yè)面
  _getDrawerItemWidget(int selectedDrawerIndex) {
    switch(selectedDrawerIndex){
      case 0:
        return WidgetMenuHome();
        break;
      case 1:
        return WidgetMenuAbout();
        break;
    }
  }
/// 在_buildActions函數(shù)中的組件onPressed的時(shí)候調(diào)用,這樣就可以更新UI
  setState(() {
            _selectedDrawerIndex = 0;
          });

好了這期我們就先這樣,學(xué)習(xí)到此結(jié)束,下期繼續(xù)。

總結(jié)

這次主要是對(duì)Scaffold的使用,以及如何構(gòu)建不同平臺(tái)的UI,確切說(shuō)是不同寬度屏幕的構(gòu)建,實(shí)現(xiàn)了大屏幕的Menu菜單,和小屏幕的Drawer菜單顯示,而且沒(méi)有考慮分包,下期將進(jìn)行分包設(shè)計(jì),并往頁(yè)面里面填充內(nèi)容,來(lái)構(gòu)建我們的需求UI 實(shí)現(xiàn)一個(gè)Flutter Jetpack,并把之前做的Android Jetpack也挪過(guò)來(lái)。

項(xiàng)目開源鏈接

Android Jetpack WebSite
Flutter Jetpack WebSite
Flutter Jetpack Github Source Code
Android Jetpack Github Source Code

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容