在我们开发过程中经常会使用到悬浮菜单的使用,当我们滑动到指定位置后,菜单会自动悬浮。
实现效果如下(左为滑动前、右为滑动后):
上述便是通过NestedScrollView 、SliverAppBar实现的效果,通过两个控件我们便可以实现上述的效果。
废话不多说直接上代码,代码的实现原理会以注释的形式实现:
- import 'package:aboxmini/view/home/room/room_device_page.dart';
- import 'package:flutter/material.dart';
- import '../../model/app_model.dart';
-
- class HomeTabBar extends StatefulWidget {
-
- const HomeTabBar({super.key});
-
- @override
- State
createState() => _HomeTabBarState(); - }
-
- class _HomeTabBarState extends State<HomeTabBar> with TickerProviderStateMixin {
- /// 自定义的一个类,此类可获取屏幕宽度等
- final AppModel _appModel = AppModel.share();
- /// 设置 中间展示区域的高度
- final double _topHeight = 180 + AppModel.share().safeTop + kToolbarHeight;
- /// 分栏控制器
- late TabController tabController = TabController(length: 3, vsync: this);
- /// 分栏控制器每一个标题
- final _tabs = <String>["Tab 1", "Tab 2", "Tab 3"];
-
- @override
- void dispose() {
- tabController.dispose();
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- return DefaultTabController(
- length: _tabs.length,
- child: NestedScrollView(
- headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
- return
[ - SliverOverlapAbsorber(
- handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
- sliver: SliverAppBar(
- /// 取消系统导航左边按钮
- leading: Container(),
- /// 设置背景色
- backgroundColor: Colors.white,
- /// 设置左边按钮宽度
- leadingWidth: _appModel.width,
- centerTitle: false,
- pinned: true,
- floating: false,
- snap: false,
- primary: true,
- /// 设置分栏区域上面的高度
- expandedHeight: 230.0,
- elevation: 10,
- //是否显示阴影,直接取值innerBoxIsScrolled,展开不显示阴影,合并后会显示
- forceElevated: innerBoxIsScrolled,
- ///自定义导航和中间内容的展示
- flexibleSpace: _displayNavAndEnvInfo(),
- /// TabBar 分栏标题
- bottom: _addTabBar(),
- ),
- ),
- ];
- },
- /// 分栏展示的页面信息
- body: _addTabBarView(),
- ),
- );
- }
-
- /// 自定义导航和中间内容展示
- Widget _displayNavAndEnvInfo() {
- return Container(
- color: Colors.white,
- width: _appModel.width,
- height: _topHeight,
- child: Column(
- children:
[ - _addNav(),
- _displayEnvDevice(),
- ],
- ),
- );
- }
-
- /// 自定义导航 可随意定制
- Widget _addNav() {
- return SizedBox(
- width: _appModel.width,
- height: _appModel.safeTop + kToolbarHeight,
- child: Container(
- margin: EdgeInsets.only(top: _appModel.safeTop),
- height: kToolbarHeight,
- width: _appModel.width,
- alignment: Alignment.centerLeft,
- child: Row(
- children:
[ - GestureDetector(
- onTap: () {
- widget.z.toggle!();
- },
- child: Row(
- children: [
- Container(
- margin: const EdgeInsets.only(left: 12, right: 6),
- child: const Icon(
- Icons.menu,
- size: 20,
- color: Colors.red,
- ),
- ),
- Text("${_appModel.currentDatum?.hostname ?? ""}"),
- ],
- ),
- ),
- Expanded(child: Container())
- ],
- ),
- ),
- );
- }
-
- /// 导航和TabBar中间展示的内容,可随意自定义
- Widget _displayEnvDevice() {
- return Container(
- color: Colors.white,
- );
- }
-
- /// TabBar 展示样式自定义,可以滚动并且居左展示
- PreferredSize _addTabBar() {
- return PreferredSize(
- /// 设置高度
- preferredSize: const Size.fromHeight(35),
- child: Align(
- /// 设置展示方式
- alignment: Alignment.centerLeft,
- /// TabBar选中、未选中样式
- child: TabBar(
- /// 是否允许滚动
- isScrollable: true,
- unselectedLabelColor: Colors.black54,
- unselectedLabelStyle: const TextStyle(fontSize: 15),
- labelColor: Colors.blue,
- labelStyle:
- const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
- indicatorSize: TabBarIndicatorSize.label,
- tabs: _tabs.map((String name) => Tab(text: name)).toList(),
- ),
- ),
- );
- }
-
- /// TabBar 分栏下的各个页面
- Widget _addTabBarView() {
- return TabBarView(
- children: _tabs.map((String name) {
- // 分栏下的页面(可随意定义、也可以设置成Text等控件),实现方式还有其他方式
- return RoomDevicePage();
- }).toList(),
- );
- }
- }
以上便是菜单悬浮的效果实现,注释写的很详细,直接粘贴复制即可实现。