Flutter自定义PageView求助:实现3页面带透明度与缩放效果
自定义带缩放&透明度效果的Flutter PageView实现方案
直接用原生PageView结合Transform、Opacity和PageController就能实现需求,不需要依赖第三方包,核心是利用页面偏移量动态计算每个页面的变换参数:
核心实现步骤
- 配置PageController:设置
viewportFraction小于1,让页面宽度小于屏幕,从而显示左右相邻页面 - 监听页面偏移:通过
AnimatedBuilder监听PageController的动画状态,实时计算每个页面的缩放和透明度值 - 应用变换效果:将计算出的参数应用到
Transform.scale和Opacity组件上
完整代码示例
import 'package:flutter/material.dart'; class CustomPageView extends StatefulWidget { const CustomPageView({super.key}); @override State<CustomPageView> createState() => _CustomPageViewState(); } class _CustomPageViewState extends State<CustomPageView> { final PageController _pageController = PageController(viewportFraction: 0.8); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: SizedBox( height: MediaQuery.of(context).size.height * 0.7, child: PageView.builder( controller: _pageController, itemCount: 5, itemBuilder: (context, index) { return AnimatedBuilder( animation: _pageController, builder: (context, child) { double pageValue = 0.0; if (_pageController.position.haveDimensions) { pageValue = _pageController.page! - index; } // 计算缩放值:当前页面为1,左右页面随偏移量缩小,最小0.7 final double scale = (1 - (pageValue.abs() * 0.3)).clamp(0.7, 1.0); // 计算透明度:和缩放关联,也可单独调整系数 final double opacity = scale; return Transform.scale( scale: scale, child: Opacity( opacity: opacity, child: child, ), ); }, child: Container( margin: const EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( color: Colors.primaries[index % Colors.primaries.length], borderRadius: BorderRadius.circular(16), ), child: Center( child: Text( "页面 $index", style: const TextStyle(fontSize: 24, color: Colors.white), ), ), ), ); }, ), ), ), ); } }
自定义调整建议
- 调整
viewportFraction(比如0.75、0.85)可以改变页面显示的宽度比例 - 修改缩放系数
0.3和透明度逻辑,能匹配目标效果图的视觉强度 - 如果需要左右页面效果不对称,可以拆分
pageValue的正负值分别计算缩放和透明度:double scale = 1.0; double opacity = 1.0; if (pageValue > 0) { // 右侧页面的缩放/透明度规则 scale = 1 - pageValue * 0.25; opacity = 1 - pageValue * 0.4; } else { // 左侧页面的缩放/透明度规则 scale = 1 + pageValue * 0.25; opacity = 1 + pageValue * 0.4; } scale = scale.clamp(0.7, 1.0); opacity = opacity.clamp(0.6, 1.0); - 保持
pageSnapping: true(默认开启)可以实现页面滑动后的吸附效果
内容的提问来源于stack exchange,提问作者Destro Shark
相关产品推荐
相关产品推荐

