Trong bài viết này, chúng ta sẽ học đc làm thế nào để tạo một animated icon bằng cách dùng AnimatedIcon widget và AnimatedIcons trong Flutter framework.
1. Create empty screen
import 'package:flutter/material.dart';
void main() => runApp(AnimatedIconDemo());
class AnimatedIconDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Coflutter - AnimatedIcon ',
home: Scaffold(
appBar: AppBar(
title: const Text('Coflutter - AnimatedIcon'),
backgroundColor: const Color(0xffae00f0),
),
body: AnimatedIconDemoScreen(),
),
);
}
}
class AnimatedIconDemoScreen extends StatefulWidget {
@override
_AnimatedIconDemoScreenState createState() =>
_AnimatedIconDemoScreenState();
}
class _AnimatedIconDemoScreenState extends
State<AnimatedIconDemoScreen> {
@override
Widget build(BuildContext context) {
return Container();
}
}
Đoạn code trên đơn giản là tạo 1 màn hình trống chứa một appbar với title “AnimatedIcon”
2. Prepare and build AnimatedIcon
AnimatedIcon widget yêu cầu 2 thuộc tính bắt buộc và cung cấp thêm 1 vài thuộc tính tuỳ chọn:
- (Required) AnimatedIconData icon: icon hiển thị. Hiện tại danh sách icons được định nghĩa sẵn cho phép chúng ta sử dụng.
- (Required) Animation<double> progress: quản lý animation cho animated icon.
- (Optional) color: màu sắc của icon.
- (Optional) size: kích thước của icon.
Theo đó, animated icon sẽ được viết như sau:
AnimatedIcon(
size: 100,
color: Colors.blue,
icon: AnimatedIcons.close_menu,
progress: _animationController,
)
// With
_animationController =
AnimationController(vsync: this,
duration: Duration(milliseconds: 500));
Cùng cập nhật code (from step 1) bằng việc thêm AnimatedIcon vào màn hình:
// ... Keep other old code
// Update _AnimatedIconDemoScreenState class
class _AnimatedIconDemoScreenState
extends State<AnimatedIconDemoScreen>
// New: Ticker for animation
with SingleTickerProviderStateMixin {
// New
AnimationController _animationController;
// New: Initialize animation controller
@override
void initState() {
super.initState();
// Create controller
_animationController =
AnimationController(vsync: this,
duration: Duration(milliseconds: 500));
}
// New: Release controller
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// New: Add animated icon at the center of screen
return Center(
child: AnimatedIcon(
size: 100,
color: Colors.blue,
icon: AnimatedIcons.close_menu,
progress: _animationController,
),
);
}
}
Ở chính giữa màn hình, chúng ta thấy kết quả 1 icon nhưng chưa thể kiểm chứng đc hiệu ứng của icon. Vậy nên bước tiếp theo chúng ta cần thêm hiệu ứng chuyển động khi user tapping vào icon.
3. Thêm hiệu ứng animation
Ở đây chúng ta sẽ bọc icon vào bên trong 1 InkWell widget và xử lý sự kiện onTap, kết hợp một biến bool để quản lý trạng thái hiện tại của icon:
class _AnimatedIconDemoScreenState extends
State<AnimatedIconDemoScreen>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
// New: icon states: show menu vs. show close.
bool isShowingMenu = false;
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this,
duration: Duration(milliseconds: 500));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
// New: Wrap icon to handle onTap event
child: InkWell(
child: AnimatedIcon(
size: 100,
color: Colors.blue,
icon: AnimatedIcons.close_menu,
progress: _animationController,
),
// New: handle onTap event
onTap: () {
// Update the state
isShowingMenu = !isShowingMenu;
if (isShowingMenu) {
// Trigger animation (start: close -> menu)
_animationController.forward();
} else {
// Trigger animation (revert: menu -> close)
_animationController.reverse();
}
},
),
);
}
}
Hoàn thành!
Dưới đây là toàn bộ code trong trường hợp bạn mong muốn trải nghiệm:
import 'package:flutter/material.dart';
void main() => runApp(AnimatedIconDemo());
class AnimatedIconDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedIcon ',
home: Scaffold(
appBar: AppBar(
title: const Text('AnimatedIcon'),
backgroundColor: const Color(0xffae00f0),
),
body: AnimatedIconDemoScreen(),
),
);
}
}
class AnimatedIconDemoScreen extends StatefulWidget {
@override
_AnimatedIconDemoScreenState createState() => _AnimatedIconDemoScreenState();
}
class _AnimatedIconDemoScreenState extends
State<AnimatedIconDemoScreen>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
// New: icon states: show menu vs. show close.
bool isShowingMenu = false;
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this,
duration: Duration(milliseconds: 500));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
// New: Wrap icon to handle onTap event
child: InkWell(
child: AnimatedIcon(
size: 100,
color: Colors.blue,
icon: AnimatedIcons.close_menu,
progress: _animationController,
),
// New: handle onTap event
onTap: () {
// Update the state
isShowingMenu = !isShowingMenu;
if (isShowingMenu) {
// Trigger animation (start: close -> menu)
_animationController.forward();
} else {
// Trigger animation (revert: menu -> close)
_animationController.reverse();
}
},
),
);
}
}