Flutter Web 网站之主页框架搭建

往期

上期回顾

上期主要完成环境的搭建和部署,最终在jetpack.net.cn地址上呈现,这期我们就开始搭建主页,构建一个可以兼容三端(Android、Ios、Web)的主页。

开始

在lib文件夹下创建home.dart文件,如图



打开文件,输入st出来的提示选择第一个,如图


这样就自动生成一个完整的模版代码,一个小小的技巧,请笑纳。最后命名PageHome,这里简单说下命名规则,只是建议,页面以Page开头,非页面以Widget开头,这样在其他地方引用的时候容易寻找,提高查找效率。接下来,我们就用一个兼容三端的组件来构建主页,不卖关子,我们使用Material主题,因为我是Android开发,更喜欢这个主题,我们在新增组件的时候总感觉很麻烦,其实也有个小技巧,如图


选第一个就可以生成一个包裹组件,继续看图


然后将widget改为Material。然后添加Padding,Scaffold组件如图



Padding的用意很简单,加一个左右边距,而在web,和手机上的边距是不一样的,不能固定死,我画个图展示展示下,如图



所以使用ResponsiveWidget判断是否是小屏幕,如果屏幕变小则使用小边距来适配,这里注意是小屏幕,不是针对的Android或者苹果手机,要注意不能混淆理解,浏览器也可以缩小到手机屏幕大小对吧,要理解ResponsiveWidget请看前期博客:一个Flutter widget自动适配不同UI到Web、Android
还有一个ScreenUtil,这个你可以理解为相当于Android中的dp单位,他负责的就是等比适配,不会让大小分辨率的屏幕看起来差距很大。这个工具有个初始化的过程

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

而且初始化必须在MaterialApp包裹中,为什么呢?因为我们使用了MediaQuery动态获取屏幕的宽高,详细请看官方文档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实现了MediaQuery的逻辑,所以你不在MaterialApp中初始化是会报错地,知道了吧。接下来看下实际运行效果,我们将内容设置成红色来看,如图


屏幕缩小后如图


这就是我们要的效果,其实已经有了两个框架封装的很完整,但前期我们为什么没有选择引用它们呢,而且他们实现的似乎更合理,请看他们的代码风格如图


一个ScreenTypeLayout这个组件实现了四个屏幕的适配,框架引用:

  responsive_builder: ^0.1.5

我为什么没有选择直接使用呢?其实我们在明白其中原理后确实可以直接引用,但我还是建议自己写一遍,通过自己的实现,更清楚其中的道理不是吗。前期的学习过程中,我们尽量的不去引用,选择自己实现,也是加快提高自己的一个办法。多多学习,多多练习。接下来我们实现Scaffold部分,Scaffold这个组件太好用了,先看下它原本的样子


,它就像一个大的容器,帮住我们组织好了各个组件的位置,是对一个基础UI的高度抽象。
简单分析下它的参数源码


其实这里最主要的三个常用的部分appBar、body、floatingActionButton,正好是我们构建一个UI的常用构造,所以这个组件基本是我们使用频率很高的一个组件,请认真学习它,更详细的学习,请看https://api.flutter.dev/flutter/material/Scaffold-class.html,这里面有几个例子,认真学习哦,我们现在通过它,来构建我们的主页代码,请看效果图:


我们先构建了AppBar的内容,怎么实现的呢,请看代码

 @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(),  /// 左边标题
          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);
          },
        ),
      ];
  }

分别通过_buildTitle,_buildActions 实现左边的标题,右边的菜单按钮,里面有个细节:


大屏幕的返回_buildActions,小屏幕直接隐藏,这里你可能有疑问,为什么不用drawer实现菜单?drawer适合小屏幕实现,而大屏慕我们就要充分利用空间,尽可能的操作简单,一目了然。下面我们来实现,小屏幕的drawer,请看代码

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

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

给Scaffold添加一个drawer组件,这里用ListView把刚才的_buildActions组件再放进来,原来是以横向展示,这次因为ListView默认是纵向,所以就是上下的展示方式,运行项目后,如图:


未展开的样子,标题右边的菜单消失



展开的样子,这就是我们要实现的小屏幕的样子。也符合手机的使用习惯。



有没有发现这个东东显示看不清楚,接下来我们改造它,可我没做过,我怎么查呢?我这里分享我的经验,首先你要明白这里的关键字是什么,当我鼠标停留在上面的时候提示如图

是一个navigation menu,所以我会在google里搜索,flutter scaffold drawer navigation menu,这么几个关键字,然后搜到的如图

,第一个是官方文档如何添加,第二个是custom drawer,自定义的,有可能讲到了如何修改,所以我就点进去寻找



看到没,还是很好找的哈,然后copy过来代码,发现它用的图不对,我们修改下,如图,这样是不是看着舒服了。


接下来就是给Scaffold的body填充内容了,先看实现的效果
Home页面黄色



About页蓝色



点击切换,具体实现请看下面代码
       int _selectedDrawerIndex = 0;
       ///定义一个坐标值
      /// 添加动态的body _getDrawerItemWidget
      child: Scaffold(
        body: _getDrawerItemWidget(_selectedDrawerIndex),
      ),
      /// 省略部分代码
      /// 根据一个index值,来确定加载哪个页面
  _getDrawerItemWidget(int selectedDrawerIndex) {
    switch(selectedDrawerIndex){
      case 0:
        return WidgetMenuHome();
        break;
      case 1:
        return WidgetMenuAbout();
        break;
    }
  }
/// 在_buildActions函数中的组件onPressed的时候调用,这样就可以更新UI
  setState(() {
            _selectedDrawerIndex = 0;
          });

好了这期我们就先这样,学习到此结束,下期继续。

总结

这次主要是对Scaffold的使用,以及如何构建不同平台的UI,确切说是不同宽度屏幕的构建,实现了大屏幕的Menu菜单,和小屏幕的Drawer菜单显示,而且没有考虑分包,下期将进行分包设计,并往页面里面填充内容,来构建我们的需求UI 实现一个Flutter Jetpack,并把之前做的Android Jetpack也挪过来。

项目开源链接

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容