Flutter Web 网站之主页框架搭建

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

往期

上期回顾

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

开始

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

image.png

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

image.png

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

image.png

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

image.png

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

image.png

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

image.png

image.png

所以使用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中初始化是会报错地,知道了吧。接下来看下实际运行效果,我们将内容设置成红色来看,如图

image.png

屏幕缩小后如图

image.png

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

image.png

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

responsive_builder: ^0.1.5

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

image.png

它就像一个大的容器,帮住我们组织好了各个组件的位置,是对一个基础UI的高度抽象。

简单分析下它的参数源码

image.png

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

image.png

我们先构建了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 实现左边的标题,右边的菜单按钮,里面有个细节:

image.png

大屏幕的返回_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默认是纵向,所以就是上下的展示方式,运行项目后,如图:

image.png

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

image.png

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

image.png

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

image.png

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

image.png

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

image.png

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

image.png

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

Home页面黄色

image.png

About页蓝色

image.png

点击切换,具体实现请看下面代码

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

目录
相关文章
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
182 45
|
1月前
|
开发框架 前端开发 定位技术
Flutter框架中的插件市场及开源资源的利用方法。内容涵盖插件市场的扩展功能、时间节省与质量保证
本文深入探讨了Flutter框架中的插件市场及开源资源的利用方法。内容涵盖插件市场的扩展功能、时间节省与质量保证,常见插件市场的介绍,选择合适插件的策略,以及开源资源的利用价值与注意事项。通过案例分析和对社区影响的讨论,展示了这些资源如何促进开发效率和技术进步,并展望了未来的发展趋势。
40 11
|
1月前
|
开发框架 数据安全/隐私保护 开发者
Flutter 是一款强大的跨平台移动应用开发框架,本文深入探讨了其布局与样式设计
Flutter 是一款强大的跨平台移动应用开发框架,本文深入探讨了其布局与样式设计,涵盖布局基础、常用组件、样式设计、实战应用、响应式布局及性能优化等方面,助力开发者打造精美用户界面。
43 7
|
1月前
|
开发框架 Dart 前端开发
Flutter 是谷歌推出的一款高效跨平台移动应用开发框架,使用 Dart 语言,具备快速开发、跨平台支持、高性能、热重载及美观界面等特点。
Flutter 是谷歌推出的一款高效跨平台移动应用开发框架,使用 Dart 语言,具备快速开发、跨平台支持、高性能、热重载及美观界面等特点。本文从 Flutter 简介、特点、开发环境搭建、应用架构、组件详解、路由管理、状态管理、与原生代码交互、性能优化、应用发布与部署及未来趋势等方面,全面解析 Flutter 技术,助你掌握这一前沿开发工具。
57 8
|
1月前
|
缓存 前端开发 数据安全/隐私保护
Flutter 框架提供了丰富的机制和方法来优化键盘处理和输入框体验
在移动应用开发中,Flutter 框架提供了丰富的机制和方法来优化键盘处理和输入框体验。本文深入探讨了键盘的显示与隐藏、输入框的焦点管理、键盘类型的适配、输入框高度自适应、键盘遮挡问题处理及性能优化等关键技术,结合实例分析,旨在帮助开发者提升应用的用户体验。
46 6
|
1月前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
1月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
38 2
|
1月前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
85 1
|
1月前
|
设计模式 移动开发 开发框架
如何学习 Flutter 框架?
学习 Flutter 需要耐心和持续的努力,通过系统的学习、实践、交流和不断跟进最新技术,你将逐渐掌握 Flutter 框架,并能够开发出高质量的移动应用。
|
1月前
|
开发框架 移动开发 Dart
Flutter 框架的缺点
以上缺点并不意味着 Flutter 框架不优秀,只是在使用过程中需要开发者根据具体的项目需求和场景,充分考虑这些因素,并采取相应的措施来克服或缓解这些问题,以充分发挥 Flutter 的优势,开发出高质量的移动应用。