Compose đi kèm với các thành phần kết hợp và đối tượng sửa đổi tích hợp sẵn để xử lý các trường hợp sử dụng ảnh động phổ biến.
Thành phần kết hợp ảnh động tích hợp sẵn
Tạo ảnh động xuất hiện và biến mất bằng AnimatedVisibility
Thành phần kết hợp AnimatedVisibility
tạo ảnh động làm xuất hiện nội dung của ảnh động và làm nội dung đó biến mất.
var visible by remember { mutableStateOf(true) } // Animated visibility will eventually remove the item from the composition once the animation has finished. AnimatedVisibility(visible) { // your composable here // ... }
Theo mặc định, nội dung xuất hiện theo kiểu rõ dần và mở rộng, và biến mất theo kiểu mờ dần và thu nhỏ. Quá trình chuyển đổi có thể được tuỳ chỉnh bởi hàm cụ thể
EnterTransition
và
ExitTransition
.
var visible by remember { mutableStateOf(true) } val density = LocalDensity.current AnimatedVisibility( visible = visible, enter = slideInVertically { // Slide in from 40 dp from the top. with(density) { -40.dp.roundToPx() } } + expandVertically( // Expand from the top. expandFrom = Alignment.Top ) + fadeIn( // Fade in with the initial alpha of 0.3f. initialAlpha = 0.3f ), exit = slideOutVertically() + shrinkVertically() + fadeOut() ) { Text( "Hello", Modifier .fillMaxWidth() .height(200.dp) ) }
Như có thể thấy trong ví dụ trên, bạn có thể kết hợp nhiều đối tượng EnterTransition
hoặc ExitTransition
với toán tử +
và mỗi đối tượng sẽ chấp nhận các tham số tuỳ chọn để tuỳ chỉnh hoạt động của đối tượng đó. Hãy xem phần tham khảo để biết thêm thông tin.
Ví dụ về EnterTransition
và ExitTransition
AnimatedVisibility
cũng cung cấp một biến thể nhận MutableTransitionState
. Biến thể này cho phép bạn kích hoạt một ảnh động ngay khi
bạn thêm AnimatedVisibility
vào cây sáng tác. Việc này cũng hữu ích khi
quan sát trạng thái ảnh động.
// Create a MutableTransitionState<Boolean> for the AnimatedVisibility. val state = remember { MutableTransitionState(false).apply { // Start the animation immediately. targetState = true } } Column { AnimatedVisibility(visibleState = state) { Text(text = "Hello, world!") } // Use the MutableTransitionState to know the current animation state // of the AnimatedVisibility. Text( text = when { state.isIdle && state.currentState -> "Visible" !state.isIdle && state.currentState -> "Disappearing" state.isIdle && !state.currentState -> "Invisible" else -> "Appearing" } ) }
Nhập và thoát hình ảnh động cho bố cục con
Nội dung trong AnimatedVisibility
(bố cục con trực tiếp hoặc gián tiếp) có thể sử dụng công cụ sửa đổi
animateEnterExit
để xác định chế độ ảnh động khác nhau cho từng thành phần. Hiệu ứng
hình ảnh cho mỗi bố cục con là sự kết hợp của các ảnh động được chỉ định
trong thành phần kết hợp AnimatedVisibility
và nhập và thoát ảnh động của riêng bố cục con.
var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn(), exit = fadeOut() ) { // Fade in/out the background and the foreground. Box( Modifier .fillMaxSize() .background(Color.DarkGray) ) { Box( Modifier .align(Alignment.Center) .animateEnterExit( // Slide in/out the inner box. enter = slideInVertically(), exit = slideOutVertically() ) .sizeIn(minWidth = 256.dp, minHeight = 64.dp) .background(Color.Red) ) { // Content of the notification… } } }
Trong một số trường hợp, bạn có thể không áp dụng AnimatedVisibility
cho ảnh động nào
để bố cục con có thể có ảnh động của riêng mình bằng
animateEnterExit
. Để đạt được mục đích này, hãy chỉ định EnterTransition.None
và
ExitTransition.None
tại thành phần kết hợp AnimatedVisibility
.
Thêm ảnh động tuỳ chỉnh
Nếu bạn muốn thêm các hiệu ứng ảnh động tuỳ chỉnh ngoài các ảnh động nhập và thoát được tích hợp sẵn, hãy truy cập phiên bản Transition
dưới đây thông qua thuộc tính transition
bên trong hàm lambda nội dung dành cho AnimatedVisibility
. Mọi trạng thái ảnh động
được thêm vào phiên bản Chuyển đổi sẽ chạy đồng thời với
các ảnh động nhập và thoát của AnimatedVisibility
. AnimatedVisibility
đợi cho đến khi
tất cả các ảnh động trong Transition
hoàn tất trước khi xoá nội dung.
Đối với các ảnh động thoát được tạo độc lập với Transition
(chẳng hạn như sử dụng
animate*AsState
), AnimatedVisibility
sẽ không thể tính đến các ảnh động đó và vì thế, có thể xoá nội dung thành phần kết hợp trước khi hoàn tất.
var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn(), exit = fadeOut() ) { // this: AnimatedVisibilityScope // Use AnimatedVisibilityScope#transition to add a custom animation // to the AnimatedVisibility. val background by transition.animateColor(label = "color") { state -> if (state == EnterExitState.Visible) Color.Blue else Color.Gray } Box( modifier = Modifier .size(128.dp) .background(background) ) }
Hãy xem updateTransition để biết thông tin chi tiết về Transition
.
Tạo ảnh động dựa trên trạng thái mục tiêu bằng AnimatedContent
Thành phần kết hợp AnimatedContent
tạo hoạt ảnh cho nội dung của nó khi thay đổi theo trạng thái mục tiêu.
Row { var count by remember { mutableIntStateOf(0) } Button(onClick = { count++ }) { Text("Add") } AnimatedContent( targetState = count, label = "animated content" ) { targetCount -> // Make sure to use `targetCount`, not `count`. Text(text = "Count: $targetCount") } }
Lưu ý phải luôn sử dụng tham số hàm lambda và phản ánh tham số đó vào nội dung. API sử dụng giá trị này làm chìa khoá để xác định nội dung hiện đang hiển thị.
Theo mặc định, nội dung ban đầu mờ dần và sau đó nội dung mục tiêu rõ dần
(hoạt động này được gọi là mờ dần qua). Bạn có thể tuỳ chỉnh hành vi ảnh động này bằng cách chỉ định đối tượng ContentTransform
cho tham số transitionSpec
. Bạn có thể tạo ContentTransform
bằng cách kết hợp EnterTransition
với ExitTransition
bằng cách sử dụng hàm infix with
. Bạn có thể áp dụng SizeTransform
cho ContentTransform
bằng cách gắn nó với hàm infix using
AnimatedContent( targetState = count, transitionSpec = { // Compare the incoming number with the previous number. if (targetState > initialState) { // If the target number is larger, it slides up and fades in // while the initial (smaller) number slides up and fades out. slideInVertically { height -> height } + fadeIn() togetherWith slideOutVertically { height -> -height } + fadeOut() } else { // If the target number is smaller, it slides down and fades in // while the initial number slides down and fades out. slideInVertically { height -> -height } + fadeIn() togetherWith slideOutVertically { height -> height } + fadeOut() }.using( // Disable clipping since the faded slide-in/out should // be displayed out of bounds. SizeTransform(clip = false) ) }, label = "animated content" ) { targetCount -> Text(text = "$targetCount") }
EnterTransition
xác định cách hiển thị của nội dung mục tiêu, còn ExitTransition
xác định cách làm biến mất nội dung ban đầu. Ngoài
tất cả các hàm EnterTransition
và ExitTransition
có sẵn cho
AnimatedVisibility
, AnimatedContent
cung cấp slideIntoContainer
và slideOutOfContainer
.
Đây là các lựa chọn thay thế thuận tiện cho slideInHorizontally/Vertically
và
slideOutHorizontally/Vertically
để tính khoảng cách trên trang trình bày dựa trên
kích thước của nội dung ban đầu và nội dung mục tiêu
của AnimatedContent
.
SizeTransform
xác định cách
kích thước sẽ tạo ảnh động giữa nội dung ban đầu và nội dung mục tiêu. Bạn có quyền
truy cập vào cả kích thước ban đầu và kích thước mục tiêu khi tạo
ảnh động. SizeTransform
cũng kiểm soát việc có nên cắt nội dung
thành kích thước thành phần trong các hình ảnh động hay không.
var expanded by remember { mutableStateOf(false) } Surface( color = MaterialTheme.colorScheme.primary, onClick = { expanded = !expanded } ) { AnimatedContent( targetState = expanded, transitionSpec = { fadeIn(animationSpec = tween(150, 150)) togetherWith fadeOut(animationSpec = tween(150)) using SizeTransform { initialSize, targetSize -> if (targetState) { keyframes { // Expand horizontally first. IntSize(targetSize.width, initialSize.height) at 150 durationMillis = 300 } } else { keyframes { // Shrink vertically first. IntSize(initialSize.width, targetSize.height) at 150 durationMillis = 300 } } } }, label = "size transform" ) { targetExpanded -> if (targetExpanded) { Expanded() } else { ContentIcon() } } }
Tạo hiệu ứng động cho hiệu ứng chuyển đổi vào và thoát của thành phần con
Cũng giống như AnimatedVisibility
, công cụ sửa đổi animateEnterExit
có sẵn bên trong nội dung hàm lambda của AnimatedContent
. Sử dụng thuộc tính này để áp dụng EnterAnimation
và ExitAnimation
cho từng bố cục con trực tiếp hoặc gián tiếp.
Thêm ảnh động tuỳ chỉnh
Giống như AnimatedVisibility
, trường transition
có sẵn bên trong
hàm lambda nội dung của AnimatedContent
. Sử dụng trường này để tạo hiệu ứng ảnh động tuỳ chỉnh
chạy đồng thời với quá trình chuyển đổi AnimatedContent
. Hãy xem
updateTransition để biết thông tin chi tiết.
Tạo ảnh động giữa hai bố cục bằng Crossfade
Crossfade
tạo ảnh động giữa hai bố cục bằng một ảnh động chuyển đổi. Bằng cách chuyển đổi,
giá trị được chuyển sang thông số current
, nội dung được chuyển đổi với
một ảnh động chuyển đổi.
var currentPage by remember { mutableStateOf("A") } Crossfade(targetState = currentPage, label = "cross fade") { screen -> when (screen) { "A" -> Text("Page A") "B" -> Text("Page B") } }
Đối tượng sửa đổi ảnh động tích hợp
Tạo ảnh động cho các thay đổi về kích thước thành phần kết hợp bằng animateContentSize
Công cụ sửa đổi animateContentSize
sẽ tạo ảnh động cho việc thay đổi về kích thước.
var expanded by remember { mutableStateOf(false) } Box( modifier = Modifier .background(colorBlue) .animateContentSize() .height(if (expanded) 400.dp else 200.dp) .fillMaxWidth() .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { expanded = !expanded } ) { }
Ảnh động cho mục danh sách
Nếu bạn đang tìm cách tạo ảnh động cho việc sắp xếp lại thứ tự mục bên trong lưới hoặc danh sách Lazy, hãy xem tài liệu ảnh động của mục bố cục lazy.
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Ảnh động dựa trên giá trị
- Ảnh động trong Compose
- Hỗ trợ công cụ tạo ảnh động {:#tooling}