公司动态

flutter实现滚动导航栏发生透明变化

📅 2026/8/22 22:35:36
flutter实现滚动导航栏发生透明变化
采用的是flutter的getx作为的状态管理product_content_view.dartimport package:flutter/material.dart; import package:flutter_app/app/components/AppBarTop.dart; import package:flutter_app/app/services/screenAdapter.dart; import package:get/get.dart; import ../controllers/product_content_controller.dart; class ProductContentView extends GetViewProductContentController { const ProductContentView({super.key}); override Widget build(BuildContext context) { return Obx(() { // ✅ Obx 包裹后opacity.value 变化会触发整个 Scaffold 重绘 final appBarBgOpacity controller.opacity.value; return Scaffold( extendBodyBehindAppBar: true, // 实现透明导航栏 appBar: AppBarTop( showBackButton: true, titleWidget: SizedBox( width: ScreenAdapter.width(400), height: ScreenAdapter.height(96), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.all(0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 商品, style: TextStyle( fontSize: ScreenAdapter.fontSize(36), color: Colors.black, ), ), Container( margin: EdgeInsets.only(top: ScreenAdapter.height(10)), width: ScreenAdapter.width(100), height: ScreenAdapter.height(2), color: Colors.red, ) ], ), ), Padding( padding: const EdgeInsets.all(0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 详情, style: TextStyle( fontSize: ScreenAdapter.fontSize(36), color: Colors.black, ), ), Container( margin: EdgeInsets.only(top: ScreenAdapter.height(10)), width: ScreenAdapter.width(100), height: ScreenAdapter.height(2), color: Colors.red, ) ], ), ), Padding( padding: const EdgeInsets.all(0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 推荐, style: TextStyle( fontSize: ScreenAdapter.fontSize(36), color: Colors.black, ), ), Container( margin: EdgeInsets.only(top: ScreenAdapter.height(10)), width: ScreenAdapter.width(100), height: ScreenAdapter.height(2), color: Colors.red, ) ], ), ), ], ), ), backgroundColor: Colors.white.withOpacity(appBarBgOpacity), actions: [ Container( margin: EdgeInsets.only(right: ScreenAdapter.width(20)), width: ScreenAdapter.width(88), height: ScreenAdapter.width(88), child: ElevatedButton( onPressed: () {}, style: ButtonStyle( //注意:去掉button默认的padding padding: MaterialStateProperty.all(const EdgeInsets.all(0)), alignment: Alignment.center, backgroundColor: MaterialStateProperty.all( Colors.black12.withOpacity(0.1 appBarBgOpacity * 0.02), ), foregroundColor: MaterialStateProperty.all(Colors.white), shape: MaterialStateProperty.all( const CircleBorder(), ), ), child: Icon( Icons.file_upload_outlined, color: appBarBgOpacity 0.5 ? Colors.black : Colors.white, )), ), Container( margin: EdgeInsets.only(right: ScreenAdapter.width(20)), width: ScreenAdapter.width(88), height: ScreenAdapter.width(88), child: ElevatedButton( onPressed: () {}, style: ButtonStyle( //注意 padding: MaterialStateProperty.all(const EdgeInsets.all(0)), alignment: Alignment.center, backgroundColor: MaterialStateProperty.all( Colors.black12 .withOpacity(0.1 appBarBgOpacity * 0.02), ), foregroundColor: MaterialStateProperty.all(Colors.white), shape: MaterialStateProperty.all(const CircleBorder())), child: Icon( Icons.more_horiz_rounded, color: appBarBgOpacity 0.5 ? Colors.black : Colors.white, )), ), ], ), body: ListView( // ✅ 必须把 controller 的 scrollController 绑定到 ListView否则 listener 永远不触发 controller: controller.scrollController, children: [ Container( width: ScreenAdapter.width(1080), height: ScreenAdapter.height(780), color: Colors.orange, ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ListTile( title: Text(我是一个内容列表), ), ], ), ); }); } }product_content_controllerimport package:flutter/material.dart; import package:get/get.dart; class ProductContentController extends GetxController { final ScrollController scrollController ScrollController(); /// 导航栏透明度0~1 final RxDouble opacity 0.0.obs; /// 触发完全不透明的滚动距离阈值 final double opacityThreshold 200; override void onInit() { super.onInit(); scrollController.addListener(_onScroll); } void _onScroll() { // 还没 attach 到 viewport 时 position 可能不存在防止报错 if (!scrollController.hasClients) return; final pixels scrollController.position.pixels; if (pixels 0) { opacity.value 0; } else if (pixels opacityThreshold) { opacity.value 1; } else { // 0 ~ threshold 之间做线性插值范围始终在 0~1 opacity.value (pixels / opacityThreshold).clamp(0.0, 1.0); } } override void onReady() { super.onReady(); } override void onClose() { scrollController.removeListener(_onScroll); scrollController.dispose(); super.onClose(); } }