Flutter Web:根据浏览器窗口改变布局大小

简介: 之前我们通过flutter开发web应用,然后用electron打包成可执行文件在pc端使用,因为electron可以设置最小宽高,所以布局不会越界,但是如果直接在浏览器中打开,因为浏览器的大小无法控制,如果用户缩小浏览器会导致布局越界。根据大部分网站的经验来看,当窗口缩小到一定程度后,布局就不会再改变,反而是增加了滚动,这样就保证了布局的正确性,所以我们也打算这么做。

前言


之前我们通过flutter开发web应用,然后用electron打包成可执行文件在pc端使用,因为electron可以设置最小宽高,所以布局不会越界,但是如果直接在浏览器中打开,因为浏览器的大小无法控制,如果用户缩小浏览器会导致布局越界。根据大部分网站的经验来看,当窗口缩小到一定程度后,布局就不会再改变,反而是增加了滚动,这样就保证了布局的正确性,所以我们也打算这么做。


监听窗口改变


经过测试,当浏览器窗口改变的时候,并不会执行页面的重绘,所以我们需要想办法监听窗口的改变。

这就需要用到window,先引入


import 'dart:html';
复制代码


然后通过window的onResize来监听,如下:


window.onResize.listen((event) {
  ...
});
复制代码


这里我们实现了监听,但是如何获取窗口的大小,同样还是用window


window.innerWidth
window.innerHeight
复制代码


这样就得到了窗口的大小。


实现滚动布局


滚动布局很简单,通过SingleChildScrollView即可,但是因为可能是两个方向的滚动,所以需要两个SingleChildScrollView嵌套。


Scrollbar(
  isAlwaysShown: true,
  child: SingleChildScrollView(
    scrollDirection: Axis.horizontal,
    child: SingleChildScrollView(
      child: appContent,
    ),
  ),
)
复制代码


这里第一个SingleChildScrollView是横向滚动,并且在外层给它添加了一个滚动条(因为windows机器的鼠标可能不支持横向滚动),然后里面在嵌套一个竖向滚动,最里面就是页面布局。


这样有一个问题,因为两层滚动所以整个布局是无限大的,加载真正的页面的时候就会报错:

RenderSemanticsAnnotations object was given an infinite size during layout.


所以我们要为页面大小加上宽高限制,首先想到的就是在Container的constraints中加入minHeight和minWidth,这是我们的目的


Scrollbar(
  isAlwaysShown: true,
  child: SingleChildScrollView(
    scrollDirection: Axis.horizontal,
    child: SingleChildScrollView(
      child: Container(
        constraints: BoxConstraints(
          minHeight: 720,
          minWidth: 1280
        ),
        child: widget.content,
      ),
    ),
  ),
)
复制代码


但是结果还是报错,因为虽然限制了宽高的最小值,最大值依然是无限大。所以还要加上最大值的限制?


我们可以继续在BoxConstraints中加上maxHeight和maxWidth,但是因为两个SingleChildScrollView导致整个空间是无限大的,所以页面会一直保持maxHeight和maxWidth,这样即使我们缩小一点浏览器而空间依然足够的情况下,页面就会需要滚动而不是压缩排列。


最终我们决定,通过计算来获取宽高,整体代码如下:


class AppContent extends StatefulWidget{
  Widget content;
  AppContent(this.content);
  @override
  State<StatefulWidget> createState() {
    return _AppContent();
  }
}
class _AppContent extends State<AppContent>{
  @override
  Widget build(BuildContext context) {
    return Scrollbar(
      isAlwaysShown: true,
      child: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: SingleChildScrollView(
          child: Container(
            width: max(window.innerWidth.toDouble(), 1280),
            height: max(window.innerHeight.toDouble(), 720),
            child: widget.content,
          ),
        ),
      ),
    );
  }
  @override
  void initState() {
    window.onResize.listen((event) {
      setState(() {
      });
    });
  }
}
复制代码


可以看到,我们通过窗口大小与我们设置的最小尺寸进行比较取较大值,这样就保证了及时窗口很小页面也不会过小而引起越界,而且可以通过滚动来浏览整个页面。

然后我们在App中用AppContent包裹整个app的页面即可。


FittedBox替代


上面有两层滚动布局虽然可以实现我们的效果,但是在浏览器中实际效果不尽人意,因为两个方向上都有滚动,所以在操作时页面很容易移动,而且如果页面上有js拖动效果的(即在HtmlElementView中有一个div通过js实现拖动),在拖动div的同时页面也会跟着动,所以我尝试了更多的widget,最终决定用FittedBox替代,最终代码如下:


class AppContent extends StatefulWidget{
  Widget content;
  AppContent(this.content);
  @override
  State<StatefulWidget> createState() {
    return _AppContent();
  }
}
class _AppContent extends State<AppContent>{
  @override
  Widget build(BuildContext context) {
    return FittedBox(
      fit: BoxFit.cover,
      alignment: Alignment.topLeft,
      child: Container(
        width: max(window.innerWidth.toDouble(), 1280),
        height: max(window.innerHeight.toDouble(), 720),
        child: widget.content,
      ),
    );
  }
  @override
  void initState() {
    window.onResize.listen((event) {
      setState(() {
      });
    });
  }
}
复制代码


BoxFit.cover是按原尺寸填充,所以child可以超出FittedBox的范围。这样虽然不能滑动(如果窗口过小,即使可以滑动也不符合我们的业务需求,所以我们会建议用户全屏,这个仅仅是为了防止用户缩小窗口导致页面溢出错乱),但是页面不会出现溢出的现象。


替换成FittedBox后,滑动问题解决了。但是在浏览器中测试的实际效果与BoxFit.cover描述不太一致,当窗口缩小的时候,内部组件同步缩小了,当缩小到一定程度后才不会继续缩小,这时候页面才会开始显示部分。虽然与期望效果不一致,不过也无所谓,也算达到了需求要求。


目录
相关文章
|
3月前
|
编解码 前端开发 JavaScript
.NET_web前端框架_layui_栅格布局
【8月更文挑战第27天】
46 4
|
3月前
|
Web App开发 iOS开发
Web 浏览器
【8月更文挑战第27天】Web 浏览器。
57 2
|
1天前
|
人工智能 前端开发 计算机视觉
Inpaint-Web:纯浏览器端实现的开源图像处理工具
在刷短视频时,常看到情侣在景区拍照被路人“抢镜”,男朋友用手机将路人“P”掉,既贴心又有趣。最近我发现了一个纯前端实现的开源项目——inpaint-web,可在浏览器端删除照片中的部分内容,非常酷。该项目基于 WebGPU 和 WASM 技术,支持图像修复与放大,已在 GitHub 上获得 5.1k Star。项目地址:[GitHub](https://github.com/lxfater/inpaint-web)。
13 3
 Inpaint-Web:纯浏览器端实现的开源图像处理工具
|
15天前
|
开发者 容器
Flutter&鸿蒙next 布局架构原理详解
本文详细介绍了 Flutter 中的主要布局方式,包括 Row、Column、Stack、Container、ListView 和 GridView 等布局组件的架构原理及使用场景。通过了解这些布局 Widget 的基本概念、关键属性和布局原理,开发者可以更高效地构建复杂的用户界面。此外,文章还提供了布局优化技巧,帮助提升应用性能。
78 4
|
15天前
|
容器
深入理解 Flutter 鸿蒙版的 Stack 布局:适配屏幕与层叠样式布局
Flutter 的 Stack 布局组件允许你将多个子组件层叠在一起,实现复杂的界面效果。本文介绍了 Stack 的基本用法、核心概念(如子组件层叠、Positioned 组件和对齐属性),以及如何使用 MediaQuery 和 LayoutBuilder 实现响应式设计。通过示例展示了照片展示与文字描述、动态调整层叠布局等高级用法,帮助你构建更加精美和实用的 Flutter 应用。
105 2
|
29天前
|
前端开发 开发者 容器
构建响应式Web界面:Flexbox与Grid布局的深度解析
【10月更文挑战第11天】本文深入解析了CSS3中的Flexbox和Grid布局,探讨了它们的特点、应用场景及使用方法。Flexbox适用于一维布局,如导航栏;Grid布局则适用于二维布局,如复杂网格。通过示例代码和核心属性介绍,帮助开发者灵活构建响应式Web界面。
51 5
|
27天前
|
容器
Flutter&鸿蒙next 布局架构原理详解
Flutter&鸿蒙next 布局架构原理详解
|
1月前
|
Android开发 开发者 容器
flutter:&UI布局 (六)
本文档介绍了Flutter中的UI布局方式,包括线性布局(如Column和Row)、非线性布局(如Stack、Flex、Positioned)以及Wrap布局等。通过具体示例代码展示了如何使用这些布局组件来构建灵活多变的用户界面,例如使用Column垂直排列文本、使用Stack叠加组件、以及利用Wrap实现自动换行的按钮布局等。
|
1月前
|
Web App开发 XML JavaScript
Python 操作浏览器:让 Python 和 Web 世界合二为一
Python 操作浏览器:让 Python 和 Web 世界合二为一
|
28天前
|
算法 安全 前端开发
基于postMessage和BroadcastChannel实现浏览器跨Tab窗口通信的方法介绍
基于postMessage和BroadcastChannel实现浏览器跨Tab窗口通信的方法介绍
74 0