Animation và Custom Painting Trong Flutter
Lập trình
5 phút đọc

Tác giả
Chuyên gia lập trình
Animation và Custom Painting Trong Flutter
Animation Cơ bản
AnimationController
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { late AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 2), vsync: this, ); } @override void dispose() { _controller.dispose(); super.dispose(); } }
Tween Animation
final animation = Tween<double>( begin: 0, end: 300, ).animate(_controller);
Các Loại Animation
Implicit Animations
AnimatedContainer( duration: Duration(milliseconds: 500), width: _isExpanded ? 300.0 : 100.0, height: _isExpanded ? 300.0 : 100.0, color: _isExpanded ? Colors.blue : Colors.red, curve: Curves.fastOutSlowIn, )
Hero Animation
Hero( tag: 'imageHero', child: Image.network('url_to_image'), )
Staggered Animations
class StaggeredAnimation extends StatelessWidget { final Animation<double> controller; late final Animation<double> opacity; late final Animation<double> width; late final Animation<double> height; StaggeredAnimation({required this.controller}) { opacity = Tween<double>( begin: 0.0, end: 1.0, ).animate( CurvedAnimation( parent: controller, curve: Interval(0.0, 0.100, curve: Curves.ease), ), ); } }
Custom Painting
CustomPaint và CustomPainter
class MyPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.blue ..strokeWidth = 4 ..style = PaintingStyle.stroke; canvas.drawCircle( Offset(size.width / 2, size.height / 2), 100, paint, ); } @override bool shouldRepaint(CustomPainter oldDelegate) => false; }
Vẽ Đường Cong
void drawCurve(Canvas canvas, Size size) { var path = Path(); path.moveTo(0, size.height / 2); path.quadraticBezierTo( size.width / 2, 0, size.width, size.height / 2, ); canvas.drawPath(path, paint); }
Hiệu Ứng Nâng Cao
Particle System
class Particle { Offset position; double speed; double theta; Color color; void update() { final dx = speed * cos(theta); final dy = speed * sin(theta); position += Offset(dx, dy); } void draw(Canvas canvas) { final paint = Paint()..color = color; canvas.drawCircle(position, 2, paint); } }
Shader Effects
final shader = LinearGradient( colors: [Colors.blue, Colors.red], ).createShader(Rect.fromLTWH(0, 0, size.width, size.height)); final paint = Paint()..shader = shader;
Performance Optimization
Repaint Boundary
RepaintBoundary( child: CustomPaint( painter: MyPainter(), ), )
Caching Complex Paintings
class CachedPainter extends CustomPainter { ui.Picture? _cachedPicture; void _createCachedPicture(Size size) { final recorder = ui.PictureRecorder(); final canvas = Canvas(recorder); // Draw complex stuff _cachedPicture = recorder.endRecording(); } }
Best Practices
Animation
- Sử dụng
vsyncđể tránh memory leak - Dispose AnimationController khi widget bị dispose
- Sử dụng Implicit Animation khi có thể
- Tránh animation quá phức tạp trên mobile
Custom Painting
- Sử dụng RepaintBoundary để tối ưu hiệu năng
- Cache các painting phức tạp
- Tránh vẽ lại không cần thiết