FlutterAndroid开发经验谈Android开发

Flutter Web 网站之主页框架搭建

2020-04-12  本文已影响0人  i校长

往期

上期回顾

上期主要完成环境的搭建和部署,最终在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

上一篇下一篇

猜你喜欢

热点阅读