Flutter: Hướng dẫn Animation
Giải phóng thời gian, khai phóng năng lực
Mục lục bài viết:
Bạn sẽ học
- Cách sử dụng các lớp cơ bản từ thư viện hoạt ảnh để thêm hoạt ảnh vào một widget.
- Khi nào thì sử dụng
AnimatedWidget
vàAnimatedBuilder
.
Hướng dẫn này chỉ cho bạn cách tạo hoạt ảnh tường minh trong Flutter. Sau khi giới thiệu một số khái niệm, lớp và phương thức thiết yếu trong thư viện hoạt ảnh, bạn sẽ được hướng dẫn qua 5 ví dụ về hoạt ảnh. Các ví dụ được xây dựng dựa trên nhau, giới thiệu cho bạn các khía cạnh khác nhau của thư viện hoạt ảnh.
Flutter SDK cũng cung cấp hoạt ảnh chuyển động ngầm định, chẳng hạn như FadeTransition
, SizeTransition
, và SlideTransition
. Những hoạt ảnh đơn giản này được kích hoạt bằng cách đặt điểm bắt đầu và điểm kết thúc. Chúng dễ triển khai hơn các hoạt ảnh tường minh.
Các khái niệm và lớp hoạt ảnh cơ bản
Vấn đề ở đây là gì?
- Animation, một lớp cốt lõi trong thư viện hoạt ảnh của Flutter, nội suy các giá trị được sử dụng để hướng dẫn hoạt ảnh.
- Một đối tượng
Animation
biết trạng thái hiện tại của hoạt ảnh (ví dụ: cho dù nó được bắt đầu, dừng lại hay đang di chuyển về phía trước hoặc ngược lại), nhưng không biết gì về những gì xuất hiện trên màn hình. - Một AnimationController để quản lý
Animation
. - Một CurvedAnimation để định nghĩa tiến trình là một đường cong phi tuyến tính.
- Một Tween để nội suy giữa phạm vi dữ liệu được sử dụng bởi đối tượng đang được làm động. Ví dụ:
Tween
có thể định nghĩa một phép nội suy từ màu đỏ sang màu xanh lam hoặc từ 0 đến 255. - Sử dụng
Listener
s vàStatusListener
s để theo dõi các thay đổi trạng thái hoạt ảnh.
Hệ thống hoạt ảnh trong Flutter dựa trên các đối tượng Animation được định kiểu. Các widget có thể kết hợp các hoạt ảnh này trực tiếp trong các hàm xây dựng của chúng bằng cách đọc giá trị hiện tại của chúng và lắng nghe các thay đổi trạng thái của chúng hoặc chúng có thể sử dụng các hoạt ảnh làm cơ sở cho các hoạt ảnh phức tạp hơn mà chúng chuyển cho các widget khác.
Animation<double>
Trong Flutter, đối tượng Animation
không hề biết gì về màn hình. Animation
là một lớp trừu tượng hiểu giá trị hiện tại và trạng thái của nó (đã hoàn thành hoặc bị loại bỏ). Một trong những kiểu hoạt ảnh được sử dụng phổ biến hơn là Animation<double>
.
Một đối tượng Animation
tuần tự tạo ra các số nội suy giữa hai giá trị trong một khoảng thời gian nhất định. Đầu ra của đối tượng Animation
có thể là tuyến tính, một đường cong, một hàm bước hoặc bất kỳ ánh xạ nào khác mà bạn có thể tạo ra. Tùy thuộc vào cách Animation
được điều khiển, nó có thể chạy ngược lại hoặc thậm chí chuyển hướng ở giữa.
Hoạt ảnh cũng có thể nội suy các loại khác với double, chẳng hạn như Animation<Color>
hoặc Animation<Size>
.
Mỗi đối tượng Animation
đều có trạng thái. Giá trị hiện tại của nó luôn có sẵn trong phương thức .value
.
Animation
không biết gì về kết xuất hoặc các hàm build()
.
CurvedAnimation
CurvedAnimation định nghĩa tiến trình của hoạt ảnh là một đường cong phi tuyến tính.
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
Lưu ý: Lớp Curves định nghĩa nhiều đường cong thường được sử dụng, hoặc bạn có thể tạo riêng của bạn. Ví dụ:
import 'dart:math'; class ShakeCurve extends Curve { @override double transform(double t) => sin(t * pi * 2); }
Duyệt qua tài liệu Curves để có danh sách đầy đủ (với bản xem trước trực quan) về các hằng Curves
đi kèm với Flutter.
CurvedAnimation
và AnimationController
(được mô tả trong phần tiếp theo) đều thuộc loại Animation<double>
, vì vậy bạn có thể truyền chúng thay thế cho nhau. CurvedAnimation
sẽ gộp đối tượng mà nó đang sửa đổi - bạn không phân lớp AnimationController
để triển khai một đường cong.
AnimationController
AnimationController là một đối tượng Animation
đặc biệt tạo ra một giá trị mới bất cứ khi nào phần cứng sẵn sàng cho một khung mới. Theo mặc định, một giá trị AnimationController
tuyến tính tạo ra các số từ 0.0 đến 1.0 trong một khoảng thời gian nhất định. Ví dụ: đoạn code sau tạo một đối tượng Animation
, nhưng không khởi động chạy nó:
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);
AnimationController
bắt nguồn từ Animation<double>
, vì vậy nó có thể được sử dụng ở bất cứ nơi nào cần đối tượng Animation
. Tuy nhiên, AnimationController
có các phương thức bổ sung để kiểm soát hoạt ảnh. Ví dụ: bạn bắt đầu một hoạt ảnh với phương thức .forward()
. Việc tạo ra các số được gắn với việc làm mới màn hình, do đó, thông thường 60 số được tạo mỗi giây. Sau mỗi số được tạo, mỗi đối tượng Animation
sẽ gọi các đối tượng Listener
đính kèm. Để tạo danh sách hiển thị tùy chỉnh cho từng con, hãy xem RepaintBoundary.
Khi tạo một AnimationController
, bạn truyền cho nó một đối số vsync
. Sự hiện diện của vsync
sẽ ngăn chặn các hoạt ảnh ngoài màn hình tiêu tốn tài nguyên không cần thiết. Bạn có thể sử dụng đối tượng trạng thái của mình làm vsync bằng cách thêm SingleTickerProviderStateMixin
vào định nghĩa lớp. Bạn có thể xem một ví dụ về điều này trong animate1 trên GitHub.
Lưu ý: Trong một số trường hợp, một vị trí có thể vượt quá phạm vi 0.0-1.0 của
AnimationController
. Ví dụ, hàmfling()
cho phép bạn cung cấp vận tốc, lực và vị trí (thông qua đối tượng Force). Vị trí có thể là bất kỳ thứ gì và vì vậy có thể nằm ngoài phạm vi 0.0-1.0.
CurvedAnimation
cũng có thể vượt quá phạm vi 0.0-1.0, ngay cả khiAnimationController
không vượt quá. Tùy thuộc vào đường cong được chọn, đầu ra củaCurvedAnimation
có thể có phạm vi rộng hơn đầu vào. Ví dụ: các đường cong đàn hồi chẳng hạn nhưCurves.elasticIn
vượt quá mức đáng kể hoặc vượt quá phạm vi mặc định.
Tween
Theo mặc định, đối tượng AnimationController
nằm trong khoảng từ 0.0 đến 1.0. Nếu bạn cần một phạm vi khác hoặc một kiểu dữ liệu khác, bạn có thể sử dụng một Tween để định cấu hình hoạt ảnh để nội suy cho một phạm vi hoặc kiểu dữ liệu khác. Ví dụ: giá trị Tween
sau đây là từ -200.0 đến 0.0:
tween = Tween<double>(begin: -200, end: 0);
Tween
là đối tượng không trạng thái chỉ nhận begin
và end
. Công việc duy nhất của Tween
là định nghĩa một ánh xạ từ phạm vi đầu vào đến phạm vi đầu ra. Phạm vi đầu vào thường là 0.0 đến 1.0, nhưng đó không phải là một yêu cầu.
Tween
thừa kế từ Animatable<T>
, không phải từ Animation<T>
. Animatable
giống Animation
ở chô không cần phải xuất ra giá trị double. Ví dụ: ColorTween
chỉ định sự tiến triển giữa hai màu.
colorTween = ColorTween(begin: Colors.transparent, end: Colors.black54);
Tween
không lưu trữ bất kỳ trạng thái nào. Thay vào đó, nó cung cấp phương thức evaluate(Animation<double> animation)
áp dụng chức năng ánh xạ cho giá trị hiện tại của hoạt ảnh. Giá trị hiện tại của Animation
có thể được tìm thấy trong phương thức .value
. Phương thức evaluate cũng thực hiện một số công việc quản lý, chẳng hạn như đảm bảo rằng phần bắt đầu và kết thúc được trả về khi giá trị hoạt ảnh tương ứng là 0.0 và 1.0.
Tween.animate
Để sử dụng đối tượng Tween
thì ta gọi animate()
vào Tween
, đi qua trong đối tượng điều khiển. Ví dụ, đoạn mã sau tạo ra các giá trị nguyên từ 0 đến 255 trong khoảng thời gian 500ms.
AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this); Animation<int> alpha = IntTween(begin: 0, end: 255).animate(controller);
Lưu ý: Phương thức
animate()
trả về một Animation, không phải là một Animatable.
Ví dụ sau cho thấy một controller, một đường cong và một Tween
:
AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this); final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); Animation<int> alpha = IntTween(begin: 0, end: 255).animate(curve);
Thông báo hoạt ảnh
Đối tượng Animation có thể có nhiều Listener
và nhiều StatusListener
, được định nghĩa với các phương thức tương ứng là addListener()
và addStatusListener()
. Listener
được gọi bất cứ khi nào giá trị của hoạt ảnh thay đổi. Hành vi phổ biến nhất của Listener
là gọi setState()
để gây dựng lại. StatusListener
được gọi khi một hoạt ảnh bắt đầu, kết thúc, di chuyển về phía trước hoặc di chuyển ngược lại, như được định nghĩa bởi AnimationStatus
. Phần tiếp theo có một ví dụ về phương thức addListener()
và Giám sát tiến trình của hoạt ảnh có một ví dụ về addStatusListener()
.
Ví dụ về hoạt ảnh
Phần này sẽ hướng dẫn bạn qua 5 ví dụ về hoạt ảnh. Mỗi phần cung cấp một liên kết đến mã nguồn cho ví dụ đó.
Kết xuất hoạt ảnh
Vấn đề ở đây là:
- Cách thêm hoạt ảnh cơ bản vào tiện ích con bằng cách sử dụng
addListener()
vàsetState()
. - Mỗi khi Animation tạo ra một số mới thì phương thức
addListener()
sẽ gọisetState()
. - Cách định nghĩa một
AnimationController
với tham sốvsync
bắt buộc. - Hiểu cú pháp "
.."
trong "..addListener
", còn được gọi là ký hiệu phân tầng của Dart. - Để đặt một lớp ở chế độ riêng tư, hãy bắt đầu tên của nó bằng dấu gạch dưới (
_
).
Cho đến thời điểm này thì bạn đã học được cách tạo một chuỗi số theo thời gian, nhưng không có gì được hiển thị (render) trên màn hình. Để hiển thị với một đối tượng Animation
, hãy lưu trữ Animation
như một thành viên của widget con của bạn, sau đó sử dụng giá trị của nó để quyết định cách vẽ.
Hãy xem ứng dụng sau đây vẽ biểu trưng Flutter mà không có hoạt ảnh:
import 'package:flutter/material.dart'; void main() => runApp(LogoApp()); class LogoApp extends StatefulWidget { _LogoAppState createState() => _LogoAppState(); } class _LogoAppState extends State<LogoApp> { @override Widget build(BuildContext context) { return Center( child: Container( margin: EdgeInsets.symmetric(vertical: 10), height: 300, width: 300, child: FlutterLogo(), ), ); } }
Nguồn ứng dụng: animate0
Phần sau cho thấy cùng một đoạn mã đã được sửa đổi để tạo hiệu ứng hoạt hình cho logo phát triển từ kích thước 0 lên kích thước đầy đủ (full size). Khi định nghĩa một AnimationController
, bạn phải truyền vào một đối tượng vsync
. Tham số vsync
được mô tả trong phần AnimationController.
Những thay đổi từ ví dụ không hoạt ảnh được đánh dấu:
Nguồn ứng dụng: animate1
Phương thức addListener()
sẽ gọi setState()
, vì vậy mỗi khi Animation
tạo ra một số điện thoại mới, khung hiện tại sẽ được đánh dấu, và build()
sẽ được gọi một lần nữa. Trong build()
, vùng chứa thay đổi kích thước vì chiều cao và chiều rộng của nó hiện sử dụng animation.value
thay vì giá trị được mã hóa cứng. Ta bỏ controller khi đối tượng State
bị loại bỏ để tránh rò rỉ bộ nhớ.
Với một vài thay đổi này, bạn đã tạo hoạt ảnh đầu tiên của mình trong Flutter!
Thủ thuật ngôn ngữ của Dart: Bạn có thể không quen với ký hiệu phân tầng của Dart - hai dấu chấm trong ..addListener()
. Cú pháp này có nghĩa là phương thức addListener()
được gọi với giá trị trả về từ animate()
. Hãy xem xét ví dụ sau:
animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() { // ··· });
Đoạn mã trên tương đương với:
animation = Tween<double>(begin: 0, end: 300).animate(controller); animation.addListener(() { // ··· });
Bạn có thể tìm hiểu thêm về ký hiệu tầng trong Tham quan Ngôn ngữ Dart.
Đơn giản hóa với AnimatedWidget
Vấn đề ở đây là:
- Cách sử dụng lớp trợ giúp AnimatedWidget (thay vì
addListener()
vàsetState()
) để tạo widget con hoạt ảnh.- Sử dụng
AnimatedWidget
để tạo một widget thực hiện hoạt ảnh có thể sử dụng lại. Để tách quá trình chuyển đổi khỏi widget, hãy sử dụng mộtAnimatedBuilder
, như được thể hiện trong phần Cấu trúc lại bằng AnimatedBuilder.- Ví dụ về các
AnimatedWidget
trong API Flutter:AnimatedBuilder
,AnimatedModalBarrier
,DecoratedBoxTransition
,FadeTransition
,PositionedTransition
,RelativePositionedTransition
,RotationTransition
,ScaleTransition
,SizeTransition
,SlideTransition
.
Lớp cơ sở AnimatedWidget
cho phép bạn tách mã widget cốt lõi khỏi mã hoạt ảnh. AnimatedWidget
không cần duy trì đối tượng State
để giữ hoạt ảnh. Ta thêm lớp AnimatedLogo
sau:
class AnimatedLogo extends AnimatedWidget { AnimatedLogo({Key key, Animation<double> animation}) : super(key: key, listenable: animation); Widget build(BuildContext context) { final animation = listenable as Animation<double>; return Center( child: Container( margin: EdgeInsets.symmetric(vertical: 10), height: animation.value, width: animation.value, child: FlutterLogo(), ), ); } }
AnimatedLogo
sử dụng giá trị hiện tại của animation
khi tự vẽ.
LogoApp
vẫn quản lý AnimationController
và Tween
, và nó truyền đối tượng Animation
tới AnimatedLogo
:
Nguồn ứng dụng: animate2
Theo dõi tiến trình của hoạt ảnh
Vấn đề ở đây là:
- Sử dụng
addStatusListener()
cho các thông báo về các thay đổi đối với trạng thái của hoạt ảnh, chẳng hạn như bắt đầu, dừng hoặc đảo ngược hướng.- Chạy hoạt ảnh trong một vòng lặp vô hạn bằng cách đảo ngược hướng khi hoạt ảnh đã hoàn thành hoặc trở lại trạng thái bắt đầu.
Thường sẽ hữu ích khi biết khi nào một hoạt ảnh thay đổi trạng thái, chẳng hạn như kết thúc, tiến lên hoặc đảo ngược. Bạn có thể nhận thông báo cho điều này với addStatusListener()
. Đoạn mã sau sửa đổi ví dụ trên để nó lắng nghe sự thay đổi trạng thái và in bản cập nhật. Dòng được đánh dấu vàng thể hiện sự thay đổi:
class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin { Animation<double> animation; AnimationController controller; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addStatusListener((state) => print('$state')); controller.forward(); } // ... }
Chạy đoạn mã trên ta được:
AnimationStatus.forward
AnimationStatus.completed
Tiếp theo, ta sử dụng addStatusListener()
để đảo ngược hoạt ảnh ở đầu hoặc cuối. Điều này tạo ra hiệu ứng "thở":
Nguồn ứng dụng: animate3
Cấu trúc lại bằng AnimatedBuilder
Vấn đề ở đây là:
- AnimatedBuilder hiểu cách hiển thị quá trình chuyển đổi.
AnimatedBuilder
không biết cách hiển thị widget, cũng như không quản lý đối tượngAnimation
.- Sử dụng
AnimatedBuilder
để mô tả hoạt ảnh như một phần của phương pháp xây dựng cho một tiện ích con khác. Nếu bạn chỉ muốn định nghĩa một tiện ích con có hoạt ảnh có thể sử dụng lại, hãy sử dụngAnimatedWidget
, như được thể hiện trong phần Đơn giản hóa với AnimatedWidget.- Ví dụ về
AnimatedBuilders
trong API Flutter:BottomSheet
,ExpansionTile
,PopupMenu
,ProgressIndicator
,RefreshIndicator
,Scaffold
,SnackBar
,TabBar
,TextField
.
Một vấn đề với code trong ví dụ animate3, đó là việc thay đổi hoạt ảnh bắt buộc phải thay đổi tiện ích hiển thị biểu trưng. Một giải pháp tốt hơn là tách các công việc thành các lớp khác nhau như sau:
- Kết xuất logo
- Định nghĩa đối tượng
Animation
- Kết xuất quá trình chuyển đổi
Bạn có thể thực hiện việc phân tách này với sự trợ giúp của lớp AnimatedBuilder
. AnimatedBuilder
là một lớp riêng biệt trong cây kết xuất. Giống như AnimatedWidget
, AnimatedBuilder
sẽ tự động lắng nghe thông báo từ đối tượng Animation
và đánh dấu cây widget đó nếu cần, vì vậy bạn không cần phải gọi addListener()
.
Cây widget cho ví dụ animate4 trông giống như sau:
Bắt đầu từ cuối cây tiện ích con, đoạn code để hiển thị icon rất đơn giản như sau:
class LogoWidget extends StatelessWidget { // Leave out the height and width so it fills the animating parent Widget build(BuildContext context) => Container( margin: EdgeInsets.symmetric(vertical: 10), child: FlutterLogo(), ); }
Ba khối ở giữa trong sơ đồ đều được tạo theo phương thức build()
trong GrowTransition
, được hiển thị bên dưới. Bản thân widget GrowTransition
là không trạng thái và chứa tập hợp các biến cuối cùng cần thiết để xác định hoạt ảnh chuyển tiếp. Hàm build() tạo và trả về AnimatedBuilder
, lấy phương thức Anonymous
( builder) và đối tượng LogoWidget
làm tham số. Công việc hiển thị quá trình chuyển đổi thực sự xảy ra trong phương thức Anonymous
(builder), phương pháp này tạo ra một kích thước Container
thích hợp để buộc LogoWidget
phải thu nhỏ lại cho vừa vặn.
Một điểm khó khăn trong đoạn mã dưới đây là con sẽ trông giống như nó được chỉ định hai lần. Điều này xảy ra là vì tham chiếu bên ngoài của con được truyền tới AnimatedBuilder
, tham chiếu này sẽ chuyển nó tới bao đóng ẩn danh, sau đó sử dụng đối tượng đó làm con của nó. Kết quả là AnimatedBuilder
được chèn vào giữa hai widget trong cây kết xuất.
class GrowTransition extends StatelessWidget { GrowTransition({this.child, this.animation}); final Widget child; final Animation<double> animation; Widget build(BuildContext context) => Center( child: AnimatedBuilder( animation: animation, builder: (context, child) => Container( height: animation.value, width: animation.value, child: child, ), child: child), ); }
Cuối cùng, đoạn code để khởi tạo hoạt ảnh trông rất giống với ví dụ animate2. Phương thức initState()
tạo ra một AnimationController
và một Tween
, sau đó liên kết chúng với animate()
. Điều kỳ diệu xảy ra trong phương thức build()
, phương thức này trả về một đối tượng GrowTransition
với một LogoWidget
như là con và một đối tượng hoạt ảnh để thúc đẩy quá trình chuyển đổi. Đây là ba yếu tố được liệt kê trong các gạch đầu dòng ở trên.
Nguồn ứng dụng: animate4
Hoạt ảnh đồng thời
Vấn đề ở đây là:
- Lớp Curves định nghĩa một loạt các đường cong thường được sử dụng mà bạn có thể sử dụng với một CurvedAnimation.
Trong phần này, bạn sẽ xây dựng dựa trên ví dụ từ việc theo dõi tiến trình của hoạt ảnh (animate3 ), được sử dụng AnimatedWidget
để tạo hoạt ảnh vào và ra liên tục. Hãy xem xét trường hợp bạn muốn tạo hoạt ảnh trong và ngoài trong khi độ mờ chuyển động từ trong suốt sang mờ đục.
Lưu ý: Ví dụ này cho thấy cách sử dụng nhiều tween trên cùng một bộ điều khiển hoạt ảnh, trong đó mỗi tween quản lý một hiệu ứng khác nhau trong hoạt ảnh. Nó chỉ dành cho mục đích minh họa. Nếu bạn đang chỉnh sửa độ mờ và kích thước trong mã sản phẩm, bạn có thể sử dụng FadeTransition và SizeTransition thay thế.
Mỗi tween quản lý một khía cạnh của hoạt ảnh. Ví dụ:
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); sizeAnimation = Tween<double>(begin: 0, end: 300).animate(controller); opacityAnimation = Tween<double>(begin: 0.1, end: 1).animate(controller);
Bạn có thể lấy kích thước bằng sizeAnimation.value
và độ mờ bằng opacityAnimation.value
, nhưng hàm tạo AnimatedWidget
chỉ lấy một đối tượng Animation
duy nhất. Để giải quyết vấn đề này, ví dụ này sẽ tạo các đối tượng Tween
của riêng nó và tính toán các giá trị một cách rõ ràng.
Thay đổi AnimatedLogo
để đóng gói các đối tượng Tween
của chính nó và phương thức build()
của nó gọi Tween.evaluate()
trên hoạt ảnh của cha nó để tính toán các giá trị kích thước và độ mờ cần thiết. Đoạn mã sau đây hiển thị các thay đổi với các phần highlight màu vàng:
class AnimatedLogo extends AnimatedWidget { // Make the Tweens static because they don't change. static final _opacityTween = Tween<double>(begin: 0.1, end: 1); static final _sizeTween = Tween<double>(begin: 0, end: 300); AnimatedLogo({Key key, Animation<double> animation}) : super(key: key, listenable: animation); Widget build(BuildContext context) { final animation = listenable as Animation<double>; return Center( child: Opacity( opacity: _opacityTween.evaluate(animation), child: Container( margin: EdgeInsets.symmetric(vertical: 10), height: _sizeTween.evaluate(animation), width: _sizeTween.evaluate(animation), child: FlutterLogo(), ), ), ); } } class LogoApp extends StatefulWidget { _LogoAppState createState() => _LogoAppState(); } class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin { Animation<double> animation; AnimationController controller; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = CurvedAnimation(parent: controller, curve: Curves.easeIn) ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); controller.forward(); } @override Widget build(BuildContext context) => AnimatedLogo(animation: animation); @override void dispose() { controller.dispose(); super.dispose(); } }
Nguồn ứng dụng: animate5
Bước tiếp theo
Bài hướng dẫn này cung cấp cho bạn nền tảng để tạo hoạt ảnh trong Flutter bằng cách sử dụng Tweens
, nhưng có nhiều lớp khác để khám phá. Bạn có thể xem thêm các lớp Tween
chuyên biệt, hoạt ảnh dành riêng cho Material Design, ReverseAnimation
, chuyển đổi phần tử được chia sẻ (còn được gọi là hoạt ảnh Hero), mô phỏng vật lý và và phương thức fling()
. Xem trang đích hoạt ảnh để biết các tài liệu và ví dụ mới nhất hiện có.
Giải phóng thời gian, khai phóng năng lực