Flutter中如何模糊PageView Builder的前后Widget
实现PageView卡片模糊效果问题
需求
想要实现:PageView中当前显示的天气卡片保持清晰,左右两侧的卡片呈现模糊效果。
问题
已完成天气卡片(WeatherCard)和PageView的搭建,测试时尝试给未聚焦卡片添加模糊,但出现异常:
切换页面时,当前激活的卡片和上一张卡片会被模糊,下一张卡片无法实现模糊效果。
当前效果
切换页面时,当前卡片与上一张卡片均处于模糊状态,下一张卡片无模糊效果。
解决方案
问题核心在于原代码仅用index == currentPage的布尔值判断卡片状态,模糊逻辑搞反,且未利用PageView的滚动进度动态调整相邻卡片的模糊度。以下是修复后的代码:
修改后的page_view_gallary.dart
class PageviewGallery extends StatefulWidget { @override _PageviewGalleryState createState() => _PageviewGalleryState(); } class _PageviewGalleryState extends State<PageviewGallery> { final List<Map<String, dynamic>> cardData = [ { "location": "Los Angeles, CA, USA", "temperature": 15, "localTimeEpoch": 1675101764, "weatherState1": "Strong Winds", "weatherState2": "Cloudy" }, { "location": "San Andreas, CA, USA", "temperature": 15, "localTimeEpoch": 1675101764, "weatherState1": "Strong Winds", "weatherState2": "Cloudy" }, { "location": "Los Angeles, CA, USA", "temperature": 15, "localTimeEpoch": 1675101764, "weatherState1": "Strong Winds", "weatherState2": "Cloudy" }, { "location": "Los Angeles, CA, USA", "temperature": 15, "localTimeEpoch": 1675101764, "weatherState1": "Strong Winds", "weatherState2": "Cloudy" }, { "location": "Los Angeles, CA, USA", "temperature": 15, "localTimeEpoch": 1675101764, "weatherState1": "Strong Winds", "weatherState2": "Cloudy" }, ]; final PageController ctrl = PageController( viewportFraction: 0.5, ); double currentPage = 0.0; @override void initState() { super.initState(); ctrl.addListener(() { setState(() { currentPage = ctrl.page ?? 0.0; }); }); } @override void dispose() { ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: ExpandablePageView.builder( controller: ctrl, itemCount: cardData.length, physics: const BouncingScrollPhysics(), itemBuilder: (context, int index) { return _buildStoryPage(index); }, ), ), ); } Widget _buildStoryPage(int index) { // 根据卡片与当前滚动位置的差值,动态计算模糊度 double blurAmount = 0.0; final double diff = (currentPage - index).abs(); if (diff >= 1) { // 非相邻卡片,应用固定模糊值 blurAmount = 5.0; } else { // 相邻卡片,根据滚动进度平滑调整模糊度 blurAmount = diff * 5.0; } // 动态调整动画属性 final double offset = diff * 20; final double top = 100 + diff * 100; final double bottom = 100 + diff * 100; return BackdropFilter( filter: ImageFilter.blur(sigmaX: blurAmount, sigmaY: blurAmount), child: AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeOutQuint, margin: EdgeInsets.only(top: top, bottom: bottom, right: 30), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: Colors.red, boxShadow: [ BoxShadow( color: Colors.black87, blurRadius: diff * 30, offset: Offset(offset, offset), ), ], ), child: WeatherCard( location: cardData[index]["location"], temperature: cardData[index]["temperature"], localTimeEpoch: cardData[index]["localTimeEpoch"], weatherState1: cardData[index]["weatherState1"], weatherState2: cardData[index]["weatherState2"], isActive: index == currentPage.round(), ), ), ); } }
关键修改点
- 移除硬编码的
isActive状态,改用滚动进度动态判断卡片激活状态 - 监听
PageController的精确page值,实时获取滚动进度,实现平滑的模糊过渡 - 调整模糊逻辑:当前卡片模糊度为0,相邻卡片根据滚动进度动态变化,非相邻卡片固定模糊值
- 动画属性(位置、阴影)随滚动进度同步调整,提升过渡自然度
内容的提问来源于stack exchange,提问作者Asad Kareem
相关产品推荐
相关产品推荐

