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月前
|
网络协议 Shell 网络安全
实验目的1.编译安装httpd2.优化路径3.并将鲜花网站上传到web服务器为网页目录4.在客户机访问网站http://www.bdqn.com
实验目的1.编译安装httpd2.优化路径3.并将鲜花网站上传到web服务器为网页目录4.在客户机访问网站http://www.bdqn.com
163 0
|
10天前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
【4月更文挑战第9天】本文对比了Python三大Web框架Django、Flask和Pyramid。Django功能全面,适合快速开发,但学习曲线较陡;Flask轻量灵活,易于入门,但默认配置简单,需自行添加功能;Pyramid兼顾灵活性和可扩展性,适合不同规模项目,但社区及资源相对较少。选择框架应考虑项目需求和开发者偏好。
|
5天前
|
前端开发 数据挖掘 API
使用Python中的Flask框架进行Web应用开发
【4月更文挑战第15天】在Python的Web开发领域,Flask是一个备受欢迎的轻量级Web框架。它简洁、灵活且易于扩展,使得开发者能够快速地构建出高质量的Web应用。本文将深入探讨Flask框架的核心特性、使用方法以及在实际开发中的应用。
|
17天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
21天前
|
前端开发 JavaScript 数据管理
描述一个使用Python开发Web应用程序的实际项目经验,包括所使用的框架和技术栈。
使用Flask开发Web应用,结合SQLite、Flask-SQLAlchemy进行数据管理,HTML/CSS/JS(Bootstrap和jQuery)构建前端。通过Flask路由处理用户请求,模块化代码提高可维护性。unittest进行测试,开发阶段用内置服务器,生产环境可选WSGI服务器或容器化部署。实现了用户注册登录和数据管理功能,展示Python Web开发的灵活性和效率。
14 4
|
30天前
|
数据库
最全三大框架整合(使用映射)——struts.xml和web.xml配置
最全三大框架整合(使用映射)——数据库资源文件jdbc.properties
9 0
|
1月前
|
前端开发 API 网络架构
Python 如何开发出RESTful Web接口,DRF框架助力灵活实现!
Python 如何开发出RESTful Web接口,DRF框架助力灵活实现!
|
1月前
|
XML JSON API
通过Flask框架创建灵活的、可扩展的Web Restful API服务
通过Flask框架创建灵活的、可扩展的Web Restful API服务
|
1月前
|
物联网 调度 开发者
构建高效Python Web应用:异步编程与Tornado框架解析
【2月更文挑战第27天】 在处理高并发的Web应用场景时,传统的同步阻塞模型往往难以满足性能需求。本文将深入探讨Python世界中的异步编程概念,并结合Tornado这一轻量级、非阻塞式Web服务器及框架,展示如何构建高性能的Web应用。通过实例驱动的方法论,我们将剖析Tornado的核心组件,包括其IOLoop、异步HTTP客户端和服务器端处理机制,以及与协程集成的细节。文章旨在为开发者提供一套实践指南,帮助他们利用Python实现快速响应和资源高效的Web服务。
28 2
|
1月前
|
设计模式 前端开发 API
简述 Python WEB 开发常用的框架有哪些?
【2月更文挑战第26天】【2月更文挑战第88篇】简述 Python WEB 开发常用的框架有哪些?