Flutter PageView如何为viewportFraction属性添加切换动画效果
如何为
viewportFraction属性添加切换动画? 
问题原因
PageController的viewportFraction是final属性,无法直接修改。你目前直接替换PageController实例的实现方式,两个状态之间没有过渡过程,自然不会出现平滑动画。
实现方案
通过动画控制器驱动viewportFraction数值平滑过渡,过渡过程中动态生成新的PageController并同步当前页码,避免切换过程中页面跳转即可实现效果,完整可运行代码如下:
import 'dart:math'; import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) => MaterialApp( debugShowCheckedModeBanner: false, title: 'Test', theme: ThemeData(), home: const Test(), ); } class Test extends StatefulWidget { const Test({Key? key}) : super(key: key); @override State<Test> createState() => _TestState(); } class _TestState extends State<Test> with SingleTickerProviderStateMixin { bool _active = false; int _currentPage = 0; late AnimationController _animController; late Animation<double> _viewportFractionAnim; @override void initState() { super.initState(); // 初始化动画控制器 _animController = AnimationController( vsync: this, duration: const Duration(milliseconds: 300), ); // 定义viewportFraction的过渡范围和插值曲线 _viewportFractionAnim = Tween<double>(begin: 1 / 3, end: 0.85).animate( CurvedAnimation(parent: _animController, curve: Curves.easeInOut), ); } @override void dispose() { _animController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // 动画值变化时动态生成新的PageController,同步当前页码 final pageController = PageController( viewportFraction: _viewportFractionAnim.value, initialPage: _currentPage, ); return NotificationListener<ScrollNotification>( // 监听页面滚动,实时更新当前页码 onNotification: (notification) { if (notification is ScrollUpdateNotification) { _currentPage = pageController.page?.round() ?? 0; } return true; }, child: AnimatedBuilder( animation: _viewportFractionAnim, builder: (context, child) => PageView.builder( padEnds: false, controller: pageController, itemCount: 10, itemBuilder: (context, index) => GestureDetector( onTap: () { setState(() { _active = !_active; _active ? _animController.forward() : _animController.reverse(); }); }, child: Container( color: Color((Random().nextDouble() * 0xFFFFFF).toInt()) .withOpacity(1), child: Center(child: Text('$index')), ), ), ), ), ); } }
你可以自行调整动画的时长、插值曲线来匹配你的设计需求。
内容的提问来源于stack exchange,提问作者nazarpunk
相关产品推荐
相关产品推荐

