Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较

这篇具有很好参考价值的文章主要介绍了Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Flutter vs 前端 杂谈
SliverAppBar的弹性背景的显隐效果使用Html+JS怎么实现

作者李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/134149018



1. 一些AppBar效果

Flutter 中,最简单的 appbar 就是 Appbar 组件,它没有任何难点,任何刚刚入门的开发着在 Flutter 脚手架创建的计数器应用中就使用了它。但是现实的开发场景中,Appbar 组件往往难以适应复杂的需求场景。

比如以下是 “王者营地” APP (即王者荣耀官方的社区应用) 的 Appbar,这个据说也是 Flutter 实现的:
Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较,前端、桌面端、移动端、UI、构建工具,Dart语言与Flutter框架开发笔记,Dart,Flutter
这种向下滚动时,AppBar出现,向上滚到顶AppBar逐渐隐藏的效果还是比较简单,可以直接使用SliverAppBar。

与之相比,下面这个高德地图滚动方向与王者营地是相反的,并且还带有一个相遇于下面内容部分似乎在向下跑的图片:
Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较,前端、桌面端、移动端、UI、构建工具,Dart语言与Flutter框架开发笔记,Dart,Flutter

这些效果当然不是使用 Appbar 组件做的。

在 Flutter 中,最简单的随着滚动带有显影效果的appbar可以使用 SliverAppBar 组件实现。

但是实际上appbar仅仅是一个应用顶部导航的效果不仅仅局限于 Flutter 原生的 AppbarSliverAppBar 。实际上,为了实现更加灵活的 appbar,还可以考虑基于 Sliver 协议 实现外观类似的组件,将它放在页面的顶部,着很好理解,因为在 写 Web 的时候就可以这样干(事实上我就是这样干过)。因此先从一个类似的 Web 中手写的例子看起。

2. 一个Web移动端上的复杂AppBar例子

先看效果吧(其实就是模仿上面的高德地图的大概效果):
Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较,前端、桌面端、移动端、UI、构建工具,Dart语言与Flutter框架开发笔记,Dart,Flutter

(附:感谢图片来源地址,我在网络随便拿的,仅仅用于此示例,祝愿贵App、贵店铺生意红火。)

这个Appbar以及相关其它动画效果,本质上都是与滚动相关的。总结起来,我们要实现的效果如下:

  1. 页面上方有一个固定的Appbar,背景颜色为蓝色,内部包含一个输入框;

  2. 页面的上半部分有一个背景图像,通过#bg-item元素实现,并且这个元素在最下层;

  3. 页面的下半部分分为两部分:

    • #scroll-item:一个滚动元素,包含一张图片,它会随着页面的滚动而滚动,但在背景元素之上。
    • #content:一个内容区域,包含一个标题,它也会随着页面的滚动而滚动,但在滚动元素之上。
  4. 使用JavaScript监听页面的滚动事件,根据滚动距离动态改变以下效果:

    • Appbar的背景颜色透明度,使其在页面滚动时逐渐变为透明。
    • Appbar内文字的颜色透明度,同样逐渐变为透明。
    • Appbar内输入框的透明度,使其在页面滚动时逐渐变为透明。
    • 滚动元素的位置,随着页面滚动而向上移动,实现视差效果。
    • 内容区域的位置,随着页面滚动而向上移动,也实现视差效果。
  5. 使用CSS的变量--my-height定义了滚动元素的初始高度,以便在JavaScript中使用。

Web 中,要实现总体思路是通过 JavaScript 监听页面滚动事件,根据滚动距离动态改变页面元素的样式,从而实现Appbar背景颜色和文字颜色的渐变效果,以及滚动元素和内容区域的视差滚动效果。这种交互设计可以提升页面的视觉吸引力和用户体验。

Web代码如下:

<!DOCTYPE html>
<html>
<head>
    <!-- 作者信息 -->
    <!-- Author: 李俊才 -->
    <!-- Email: 291149494@163.com -->

    <!-- 许可证信息 -->
    <!-- LICENSE: MIT -->
    <style>
        body {
            margin: 0;
            padding: 0;
            --my-height: 460px;  // 定义一个CSS变量,表示滚动元素的初始高度
        }

        #appbar {
            position: fixed;
            top: 0;
            width: 100%;
            height: 50px;
            background: rgba(0, 123, 255, 1);
            color:white;
            font-size: large;
            transition: background 0.3s;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0 10px;
            padding-right: 20px;
            z-index: 3;  // 设置appbar在最上层
        }

        #appbar-input {
            padding: 5px;
            border-radius: 5px;
            border: 1px solid white;
            margin-right: 20px;
        }

        #appbar-input::placeholder {
            color: white;
        }

        #bg-item {
            position: fixed;
            top: 0;
            width: 100%;
            height: var(--my-height);
            z-index: 0;  // 设置背景元素在最下层
        }

        #bg-item img {
            width: 100%;
            height: auto;
            object-fit: cover;
        }

        #scroll-item {
            position: absolute;
            top: var(--my-height);
            width: 100%;
            z-index: 1;  // 设置滚动元素在背景元素之上
        }

        #scroll-item img {
            width: 100%;
            height: auto;
            object-fit: cover;
        }

        #content {
            position: absolute;
            top: var(--my-height);
            height: 610px;
            width: 100%;
            background-color: #ececec;
            z-index: 2;  // 设置内容元素在滚动元素之上
        }
    </style>
</head>

从CSS部分就可以看出,实际上归纳起来,我把页面拆分为了 appbar、背景图层、滚动图层、内容层,通过 z-index 属性来控制层级关系(可以结合下面html部分)。代码接上:

    <!-- 作者信息 -->
    <!-- Author: 李俊才 -->
    <!-- Email: 291149494@163.com -->

    <!-- 许可证信息 -->
    <!-- LICENSE: MIT -->
<body>
    <div id="appbar">
        <div>我是appbar</div>
        <input id="appbar-input" type="text" placeholder="我是输入框">
    </div>
    <div id="bg-item">
        <img src="https://gw.alicdn.com/imgextra/i4/2212013333132/O1CN01DetIjE1Z0VMx4155t_!!2212013333132.jpg_Q75.jpg_.webp" alt="Image">
    </div>

    <div id="scroll-item">
        <img src="https://gitee.com/jacklee1995/example-pictures/raw/master/piano/jonathanvasquez8950_piano_795a8e31-a910-48aa-9eae-45b1602f7cba.png" alt="Image"/>
    </div>
    
    <div id="content">
        <h1>我是内容区域</h1>
    </div>

    <script>
        // 获取 appbar 以及appbar内的输入框元素节点
        const appbar = document.getElementById('appbar');
        const appbarInput = document.getElementById('appbar-input');
        // 获取滚动项节点,这是一个与内容节点差速滚动的元素
        const scrollItem = document.getElementById('scroll-item');
        // 获取内容节点
        const content = document.getElementById('content');
        // 定义页面滚动的最大距离,在这个距离内appbar的背景颜色和文字颜色会发生变化
        const maxScroll = 280;

        window.addEventListener("scroll", function() {
            let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
            let opacity =  (scrollTop / maxScroll);
            opacity = opacity < 0 ? 0 : opacity;
            // 根据滚动距离动态改变appbar的背景颜色透明度
            appbar.style.background = `rgba(0, 123, 255, ${opacity})`;
            // 根据滚动距离动态改变appbar内文字的颜色透明度
            appbar.style.color = `rgba(255, 255, 255, ${opacity})`;
            appbarInput.style.opacity = `${opacity}`;
            // 根据滚动距离动态改变滚动项的位置
            scrollItem.style.top = `calc(var(--my-height) - ${scrollTop}px)`;
            // 根据滚动距离动态改变内容的位置
            content.style.top = `calc(var(--my-height) - ${scrollTop / 2}px)`;
        });
    </script>
</body>
</html>

所有的控制逻辑我在 scroll 监听中完成的,实际上就是对各个层的控制。

3. Flutter小试:我就不用SliverAppBar了

其实我的意思就是想自定义与滚动效果相关的appbar。既然需要滚动控制,而且使用 SliverAppBar 套参数也不是那么方便,即使这样的效果无非是控制一个盒子的透明度变化以及其它的位置移动。说来说去, SliverAppBar 也可以通过其它的组件实现,最后转为 Sliver 协议放入CustomScrollView不就可以了。

整体思路和 Web 中差不多,由于是分层,需要使用 StackPositioned 组件(相比于上一小节在Web中我们使用的是html+CSS的z-index,然后在 JS 代码中动态调整opacity)。

整体思路完全一样。于是,可以将上一个小节的 Web 代码 改用Flutter实现一下:

import 'package:flutter/material.dart';

// Author: 李俊才
// Email: 291149494@163.com
// https://blog.csdn.net/qq_28550263/article/details/134149018

class WebAppBarScaffold extends StatefulWidget {
  const WebAppBarScaffold({Key? key}) : super(key: key);

  
  State<WebAppBarScaffold> createState() => _WebAppBarScaffoldState();
}

class _WebAppBarScaffoldState extends State<WebAppBarScaffold> {
  double _opacity = 0.0;
  double _offsetImage = 0.0;
  double _offsetContent = 0.0;

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: NotificationListener<ScrollNotification>(
        onNotification: (ScrollNotification scrollInfo) {
          if (scrollInfo is ScrollUpdateNotification) {
            setState(() {
              _opacity = scrollInfo.metrics.pixels / 280;
              _opacity = _opacity.clamp(0.0, 1.0);
              _offsetImage = scrollInfo.metrics.pixels * 1.5; // 修改这里
              _offsetContent = scrollInfo.metrics.pixels / 2; // 修改这里
            });
          }
          return true;
        },
        child: Stack(
          children: <Widget>[
            Positioned(
              top: 0,
              child: Image.network(
                'https://gw.alicdn.com/imgextra/i4/2212013333132/O1CN01DetIjE1Z0VMx4155t_!!2212013333132.jpg_Q75.jpg_.webp',
                width: MediaQuery.of(context).size.width,
                fit: BoxFit.cover,
              ),
            ),
            Positioned(
              top: 460 - _offsetImage,
              child: Image.network(
                'https://gitee.com/jacklee1995/example-pictures/raw/master/piano/jonathanvasquez8950_piano_795a8e31-a910-48aa-9eae-45b1602f7cba.png',
                width: MediaQuery.of(context).size.width,
                fit: BoxFit.cover,
              ),
            ),
            Positioned(
              top: 460 - _offsetContent,
              child: Container(
                color: Colors.grey[200],
                width: MediaQuery.of(context).size.width,
                height: 610,
                child: const Center(child: Text('我是内容区域')),
              ),
            ),
            Positioned(
              top: 0,
              child: Container(
                width: MediaQuery.of(context).size.width,
                height: 50,
                color: Colors.blue.withOpacity(_opacity),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Padding(
                      padding: const EdgeInsets.only(left: 10),
                      child: Text(
                        '我是appbar',
                        style: TextStyle(
                            color: Colors.white.withOpacity(_opacity)),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(right: 20),
                      child: Opacity(
                        opacity: _opacity,
                        child: const SizedBox(
                          width: 200, // 限定宽度
                          child: TextField(
                            decoration: InputDecoration(
                              hintText: '我是输入框',
                              hintStyle: TextStyle(color: Colors.white),
                            ),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
            ListView.builder(
              itemCount: 1,
              itemBuilder: (context, index) {
                return Container(
                    height: MediaQuery.of(context).size.height * 2);
              },
            ),
          ],
        ),
      ),
    );
  }
}

Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较,前端、桌面端、移动端、UI、构建工具,Dart语言与Flutter框架开发笔记,Dart,Flutter
这里其实有一个小缺陷,就是滚动过头我没去做处理了。这里是一点小数学问题,就是计算中间层的图片相对于内容层图片滚动的位移值恰好为图片的高度时,让中间滚动图片层和内容层一起滚动,就可以避免看到中间滚动图层相比于内容层越来越远。读者可以尝试修改一下代码。

4. 结论

其实本文主要目的还是比较。可以看到,使用Web事件监听处理滚动事件,其实和Flutter中使用滚动控制差不多。对于一些复杂的效果,没有必要拘束于现有的组件,可以基于一些更加基础的部件构成复杂的效果。文章来源地址https://www.toymoban.com/news/detail-743164.html

到了这里,关于Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter ios 使用ListView 。滚动时 AppBar 改变颜色问题

    在Ios 中 列表滚动条向下滚动一段距离后 会导致 AppBar 颜色改变  可以给 AppBar 或者 AppBarTheme。 scrolledUnderElevation: 0.0 属性 全局: 局部: 效果:  滚动前 滚动后 x ke z

    2024年04月17日
    浏览(37)
  • 前端:纯css实现图片轮播(自动+手动)

    目录 1.图片自动轮播 2.图片手动轮播 3.补充内容 创建2个盒子,一个盒子进行轮播图展示,一个盒子用来承载图片 CSS重置reset.css normalize.css,在写页面时,由于HTML标签自带一些CSS属性,导致在调试样式的时候会出现各种奇怪的问题,为了大概率避免这些问题,在写CSS之前可以

    2024年02月04日
    浏览(55)
  • VS2017手动安装qt插件

    首先下载对应版本的qt组件: Qt Visual Studio Tools - Visual Studio Marketplace 下载好组件后,管理员运行vs的tools command  然后将下载的组件vsix拖动到窗口中,回车 然后打开vs就可以看到qt的插件了    如果qt下拉没有显示出版本,可以添加qt的qmake路径 因为我的vs自动识别了qt的qmake,所

    2024年02月12日
    浏览(38)
  • VS_Qt在项目中新建子窗体ui,并手动生成.h文件、.cpp文件(后续有问题再更改)--在VS中手动配置ui文件和类

    创建步骤及注意事项: 步骤1:创建ui文件; 方法1:通过vs中 右击项目—添加—新建项,打开下图,创建所需窗体ui 方法2:直接打开Qt Designer,创建我们所需的ui文件;创建完成后,保存到当前项目目录中,然后由vs导入ui文件到项目中; 步骤2:创建ui文件的类 首先:创建一

    2024年02月02日
    浏览(57)
  • WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)

    在现代 Web 应用程序中,实时数据推送给前端变得越来越重要。无论是实时聊天、实时通知还是仪表板上的实时更新,都需要一种有效的方式来将数据推送给前端。本文将介绍两种常用的实现方法:WebSocket 和 Server-Sent Events(SSE),并提供详细的实现步骤。 WebSocket 和 Server-S

    2024年02月05日
    浏览(42)
  • 前端 JavaScript 与 HTML 怎么实现交互?

    前端的交互性是通过JavaScript与HTML结合实现的。JavaScript作为一种脚本语言,可以嵌入HTML中,通过对DOM(文档对象模型)的操作,实现与用户的交互。以下将详细介绍前端JavaScript与HTML如何实现交互,包括事件处理、DOM操作、表单交互等方面的内容。 事件是指用户在页面上的动

    2024年01月22日
    浏览(53)
  • 前端实现 input 回车搜索(html,vue,react实现)

    搜索框是个常见的功能,除了 用ui库,有的时候必须要自己封装(因为改ui库太麻烦了,定制化要求很高),所以 涉及到 点击按钮搜索和回车搜索都要实现。下面就是实现的一些方法。 html里: 方式一:html里可以用 form 来实现,因为form里回车也能触发提交事件。思路就是

    2024年02月11日
    浏览(47)
  • web前端——HTML+CSS实现九宫格

    web前端——HTML+CSS实现九宫格

    2024年02月05日
    浏览(44)
  • web前端——HTML+CSS实现奥运五环

    web前端——HTML+CSS实现奥运五环  

    2024年02月05日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包