网站开发众筹,网站开发的形式,今天重庆发生大新闻,长沙百度搜索排名优化Flutter NestedScrollView 内嵌视图滚动行为一致 视频 https://youtu.be/_h7CkzXY3aM https://www.bilibili.com/video/BV1Gh4y1571p/ 前言 上一节讲了 CustomScrollView #xff0c;可以发现有的地方滚动并不是很连贯。 这时候就需要 NestedScrollView 来处理了。 今天会写… Flutter NestedScrollView 内嵌视图滚动行为一致 视频 https://youtu.be/_h7CkzXY3aM https://www.bilibili.com/video/BV1Gh4y1571p/ 前言 上一节讲了 CustomScrollView 可以发现有的地方滚动并不是很连贯。 这时候就需要 NestedScrollView 来处理了。 今天会写一个如下图的例子来实现滚动一致。 原文 https://ducafecat.com/blog/flutter-sliver-nested-scroll-view 参考 https://api.flutter.dev/flutter/widgets/NestedScrollView-class.html https://api.flutter.dev/flutter/widgets/SliverOverlapAbsorber-class.html https://api.flutter.dev/flutter/widgets/SliverOverlapInjector-class.html 知识点 NestedScrollView NestedScrollView 是 Flutter 中的一个 Widget它可以嵌套多个滚动视图例如 ListView、GridView、SliverAppBar 等。NestedScrollView 可以让多个滚动视图联动滚动从而实现一些复杂的交互效果。 常见的业务场景 一个页面上有多个可滚动的区域而且这些区域之间的滚动是相互独立的但是它们的滚动行为需要协调一致比如一个列表和一个悬浮的顶部栏。 实现类似于网易云音乐个人主页的效果即在滚动过程中一个悬浮的头部会被逐渐放大同时顶部的导航栏会渐变消失直到最后整个头部完全占据整个屏幕。 在列表中嵌套一个可滚动的子列表例如在一个电商应用中展示一个大分类下的多个小分类每个小分类下面又有多个商品。 NestedScrollView 和 CustomScrollView 都是支持自定义滚动视图的 Widget。它们的区别在于CustomScrollView 可以通过添加多个 Sliver 来实现复杂的滚动视图效果而 NestedScrollView 则是将多个滚动视图嵌套在一起并提供了一些方便的接口来协调它们之间的滚动。因此NestedScrollView 的使用场景更加适合于多个可滚动区域之间需要协调滚动的情况。 步骤 NestedScrollView 分为头部和内容两个部分我们分别来实现。 第一步实现 NestedScrollView 头部 lib/nested.dart 编写头部组件函数创建页面 NestedScrollPage class NestedScrollPage extends StatefulWidget { const NestedScrollPage({super.key}); override StateNestedScrollPage createState() _NestedScrollPageState();}class _NestedScrollPageState extends StateNestedScrollPage { final ListString _tabs const [tab1, tab2, tab3, tab4]; 准备 _tabs 数据 build 函数 override Widget build(BuildContext context) { return Scaffold( body: DefaultTabController( length: _tabs.length, child: NestedScrollView( headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return Widget[ _buildHeader(context, innerBoxIsScrolled), ]; }, body: _buildTabBarView(), ), ), ); } headerSliverBuilder 头部实现函数 // 头部 Widget _buildHeader(BuildContext context, bool innerBoxIsScrolled) { return // SliverOverlapAbsorber 的作用是处理重叠滚动效果 // 防止 CustomScrollView 中的滚动视图与其他视图重叠。 SliverOverlapAbsorber( handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), sliver: // SliverAppBar 的作用是创建可折叠的顶部应用程序栏 // 它可以随着滚动而滑动或固定在屏幕顶部并且可以与其他 Sliver 小部件一起使用。 SliverAppBar( title: const Text(滚动一致性), pinned: true, elevation: 6, //影深 expandedHeight: 300.0, forceElevated: innerBoxIsScrolled, //为true时展开有阴影 flexibleSpace: FlexibleSpaceBar( background: Image.asset( assets/images/banner-bg.jpg, fit: BoxFit.cover, ), ), // 底部固定栏 bottom: MyCustomAppBar( child: Column( children: [ Container( color: Colors.greenAccent, child: const Center(child: Text(固定高度内容)), ), TabBar( tabs: _tabs .map((String name) Tab( text: name, )) .toList(), ), ], ), ), ), ); } SliverOverlapAbsorber 与 SliverOverlapInjector作用是防止 CustomScrollView 中的滚动视图与其他视图重叠。 编写 MyCustomAppBar 悬停 Bar lib/app_bar.dart import package:flutter/material.dart;class MyCustomAppBar extends StatelessWidget implements PreferredSizeWidget { final Widget child; const MyCustomAppBar({super.key, required this.child}); override Widget build(BuildContext context) { return child; } override Size get preferredSize const Size.fromHeight(kToolbarHeight 20.0);} 第二步实现 NestedScrollView 内容 lib/nested.dart TabBarView 混入各种情况横向滚动、固定高度、SliverList列表 Widget _buildTabBarView() { return TabBarView( children: _tabs.map((String name) { return SafeArea( top: false, bottom: false, child: Builder( builder: (BuildContext context) { return CustomScrollView( key: PageStorageKeyString(name), slivers: Widget[ // SliverOverlapInjector 的作用是处理重叠滚动效果 // 确保 CustomScrollView 中的滚动视图不会与其他视图重叠。 SliverOverlapInjector( handle: NestedScrollView.sliverOverlapAbsorberHandleFor( context), ), // 横向滚动 SliverToBoxAdapter( child: SizedBox( height: 100, child: PageView( children: [ Container( color: Colors.yellow, child: const Center(child: Text(横向滚动)), ), Container(color: Colors.green), Container(color: Colors.blue), ], ), ), ), // 固定高度内容 SliverToBoxAdapter( child: Container( height: 100, color: Colors.greenAccent, child: const Center(child: Text(固定高度内容)), ), ), // 列表 buildContent(name), // 固定高度内容 SliverToBoxAdapter( child: Container( height: 100, color: Colors.greenAccent, child: const Center(child: Text(固定高度内容)), ), ), // 列表 100 行 SliverList( delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return ListTile(title: Text(Item $index)); }, childCount: 100, ), ), ], ); }, ), ); }).toList(), ); } SliverOverlapInjector 的作用是处理重叠滚动效果 确保 CustomScrollView 中的滚动视图不会与其他视图重叠。 内容列表 // 内容列表 Widget buildContent(String name) SliverPadding( padding: const EdgeInsets.all(8.0), sliver: SliverFixedExtentList( itemExtent: 48.0, delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return ListTile( title: Text($name - $index), ); }, childCount: 50, ), ), ); 启动 lib/main.dart import package:flutter/material.dart;import nested.dart;void main() { runApp(const MyApp());}class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. override Widget build(BuildContext context) { return MaterialApp( title: Flutter Demo, theme: ThemeData( primarySwatch: Colors.blue, useMaterial3: true, ), // home: const MyPageView(), home: const NestedScrollPage(), ); }} 直接设置 home 进入 NestedScrollPage 界面 最后完整代码 lib/app_bar.dart import package:flutter/material.dart;class MyCustomAppBar extends StatelessWidget implements PreferredSizeWidget { final Widget child; const MyCustomAppBar({super.key, required this.child}); override Widget build(BuildContext context) { return child; } override Size get preferredSize const Size.fromHeight(kToolbarHeight 20.0);} lib/nested.dart import package:flutter/material.dart;import app_bar.dart;class NestedScrollPage extends StatefulWidget { const NestedScrollPage({super.key}); override StateNestedScrollPage createState() _NestedScrollPageState();}class _NestedScrollPageState extends StateNestedScrollPage { final ListString _tabs const [tab1, tab2, tab3, tab4]; override Widget build(BuildContext context) { return Scaffold( body: DefaultTabController( length: _tabs.length, child: NestedScrollView( headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return Widget[ _buildHeader(context, innerBoxIsScrolled), ]; }, body: _buildTabBarView(), ), ), ); } // 头部 Widget _buildHeader(BuildContext context, bool innerBoxIsScrolled) { return // SliverOverlapAbsorber 的作用是处理重叠滚动效果 // 防止 CustomScrollView 中的滚动视图与其他视图重叠。 SliverOverlapAbsorber( handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), sliver: // SliverAppBar 的作用是创建可折叠的顶部应用程序栏 // 它可以随着滚动而滑动或固定在屏幕顶部并且可以与其他 Sliver 小部件一起使用。 SliverAppBar( title: const Text(滚动一致性), pinned: true, elevation: 6, //影深 expandedHeight: 300.0, forceElevated: innerBoxIsScrolled, //为true时展开有阴影 flexibleSpace: FlexibleSpaceBar( background: Image.asset( assets/images/banner-bg.jpg, fit: BoxFit.cover, ), ), // 底部固定栏 bottom: MyCustomAppBar( child: Column( children: [ Container( color: Colors.greenAccent, child: const Center(child: Text(固定高度内容)), ), TabBar( tabs: _tabs .map((String name) Tab( text: name, )) .toList(), ), ], ), ), ), ); } Widget _buildTabBarView() { return TabBarView( children: _tabs.map((String name) { return SafeArea( top: false, bottom: false, child: Builder( builder: (BuildContext context) { return CustomScrollView( key: PageStorageKeyString(name), slivers: Widget[ // SliverOverlapInjector 的作用是处理重叠滚动效果 // 确保 CustomScrollView 中的滚动视图不会与其他视图重叠。 SliverOverlapInjector( handle: NestedScrollView.sliverOverlapAbsorberHandleFor( context), ), // 横向滚动 SliverToBoxAdapter( child: SizedBox( height: 100, child: PageView( children: [ Container( color: Colors.yellow, child: const Center(child: Text(横向滚动)), ), Container(color: Colors.green), Container(color: Colors.blue), ], ), ), ), // 固定高度内容 SliverToBoxAdapter( child: Container( height: 100, color: Colors.greenAccent, child: const Center(child: Text(固定高度内容)), ), ), // 列表 buildContent(name), // 固定高度内容 SliverToBoxAdapter( child: Container( height: 100, color: Colors.greenAccent, child: const Center(child: Text(固定高度内容)), ), ), // 列表 100 行 SliverList( delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return ListTile(title: Text(Item $index)); }, childCount: 100, ), ), ], ); }, ), ); }).toList(), ); } Widget buildContent(String name) SliverPadding( padding: const EdgeInsets.all(8.0), sliver: SliverFixedExtentList( itemExtent: 48.0, delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return ListTile( title: Text($name - $index), ); }, childCount: 50, ), ), );} 代码 https://github.com/ducafecat/flutter_develop_tips/blob/main/flutter_application_sliver_scroll/lib/nested.dart 小结 使用 NestedScrollView 是一个非常强大和灵活的 widget可以实现许多常见的滚动视图布局例如带有悬浮标题的列表视图或者带有可展开/折叠部分的折叠面板。 感谢阅读本文 如果我有什么错请在评论中让我知道。我很乐意改进。 © 猫哥 ducafecat.com end