Flutter使用AnimationController与AnimatedBuilder实现容器宽度动画后欢迎页白屏求解
Flutter欢迎页动画实现白屏问题修复
触发白屏的核心原因
- 动画从未启动:初始化
AnimationController后未调用forward()方法,动画值始终处于初始状态,无任何动态变化。 - 宽度值绑定错误:Container直接使用
_controller.value作为宽度,而AnimationController的默认取值范围为0-1,即便启动动画,宽度也仅为0-1像素,完全不可见。 - 子组件未嵌套渲染:
AnimatedBuilder传入的child参数(包含logo、引导文字、登录/注册按钮的全部UI内容)没有被放入builder方法返回的Container内部,导致所有交互元素完全没有被渲染到页面上。 - 冗余状态更新:AnimatedBuilder本身会监听动画值变化自动触发重建,代码中手动添加
addListener搭配空的setState属于不必要的性能损耗。 - 冗余导入:代码中重复导入了
login_screen.dart文件,会产生编译警告。
修复后完整实现代码
import 'package:flutter/material.dart'; import 'package:animated_text_kit/animated_text_kit.dart'; import 'package:naber/screens/login_screen.dart'; import 'package:naber/screens/registration_screen.dart'; import '../widgets.dart'; import 'package:naber/constants.dart'; class WelcomeScreen extends StatefulWidget { static String id = "welcome_screen"; @override _WelcomeScreenState createState() => _WelcomeScreenState(); } class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProviderStateMixin { AnimationController _controller; Animation<double> _widthAnimation; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 4), vsync: this, ); // 绑定宽度动画取值范围 _widthAnimation = Tween<double>(begin: 1080, end: 1480).animate(_controller); // 启动动画 _controller.forward(); } @override void dispose() { // 释放动画控制器资源,避免内存泄漏 _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: AnimatedBuilder( animation: _widthAnimation, builder: (context, child) { return Container( // 使用动画生成的宽度值 width: _widthAnimation.value, decoration: BoxDecoration( image: DecorationImage( image: AssetImage(kWelcomeScreenBackgroundImage), fit: BoxFit.cover, ), ), // 将传入的UI内容嵌套到Container内部 child: child, ); }, // 无需随动画重建的静态UI直接放在child参数中,优化渲染性能 child: Padding( padding: const EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, textBaseline: TextBaseline.alphabetic, crossAxisAlignment: CrossAxisAlignment.end, children: [ Hero( tag: "logo", child: Container( child: Image.asset(kLogoImage), height: 140, ), ), TypewriterAnimatedTextKit( speed: const Duration(milliseconds: 200), text: const [kWelcomePageText], textStyle: kWelcomePageTextStyle, ), ], ), const SizedBox( height: 70, ), WelcomeScreenButtons( text: kLoginText, color1: kLoginButtonColor1, color2: kLoginButtonColor2, color3: kLoginButtonColor3, route: LoginScreen.id, ), const SizedBox(height: 15), WelcomeScreenButtons( text: kRegistrationText, color1: kRegisterButtonColor1, color2: kRegisterButtonColor2, color3: kRegisterButtonColor3, route: RegistrationScreen.id, ), ], ), ), ), ); } }
注意:硬编码的1080、1480宽度值在不同尺寸的设备上会出现适配问题,可结合
MediaQuery获取屏幕宽度动态调整Tween的起止值,同时可根据需求为动画添加repeat(reverse: true)实现循环动效。
内容的提问来源于stack exchange,提问作者ygzkrmtc
相关产品推荐
相关产品推荐

