AnimatedVisibility( //定義內容是否應該可見 visible = shown, /* slideIn、slideInVertically、slideInVertically 只能同時存在一個 enter = slideInVertically( //從離本身(小於零(上方)大於零(下方))fullHeight位置滑入 initialOffsetY = { fullHeight -> -fullHeight }, animationSpec = tween(durationMillis = 250, easing = FastOutLinearInEasing) ), enter = slideInHorizontally( //從離本身(小於零(上方)大於零(下方))fullHeight位置滑入 initialOffsetX = { fullWidth ->-fullWidth }, animationSpec = tween(durationMillis = 2500, easing = LinearOutSlowInEasing) ), */ enter = slideIn( // 從在 initialOffset 中定義的起始偏移量到 IntOffset(0, 0)。 // 滑動的方向可以通過配置initialOffset來控制。 // 正x值表示從右向左滑動,而負x值將向右滑動內容。 同樣,正負y值分別對應於向上和向下滑動。 initialOffset = { (fullWidth, fullHeight) ->IntOffset(-fullWidth,-fullHeight) }, // animationSpec配置動畫限制 // tween:配置持續時間和緩動曲線的 // repeatable:配置重復的動畫(幾次,動畫,結尾開始或從頭開始) // repeatable(5,tween(durationMillis = 2500, easing = LinearOutSlowInEasing),RepeatMode.Reverse) // infiniteRepeatable:配置重復的動畫(動畫,結尾開始或從頭開始) // spring // durationMillis過渡時間。easing速度處理,默認LinearOutSlowInEasing // FastOutSlowInEasing:先加速再減速 // LinearOutSlowInEasing:減速 // FastOutLinearInEasing:加速 // LinearEasing:勻速 animationSpec =tween(durationMillis = 2500, easing = LinearOutSlowInEasing) ) + fadeIn( //不透明度從0.1f 到 1f initialAlpha = 0.1f, animationSpec = tween(durationMillis = 2500,easing = LinearEasing) ), //scaleIn() exit = slideOutVertically( // Exits by sliding out from offset 0 to -fullHeight. targetOffsetY = { fullHeight -> -fullHeight }, animationSpec = tween(durationMillis = 250, easing = FastOutLinearInEasing) ) ) { ...... }
val alpha by infiniteTransition.animateFloat( initialValue = 0f, targetValue = 1f, animationSpec = infiniteRepeatable( animation = keyframes { durationMillis = 1000 // 添加一個關鍵幀,以便動畫值在時間為:timeStamp。 例如:0.8f at 150 // ms 0.7f at 500 }, repeatMode = RepeatMode.Reverse ) ) Row( modifier = Modifier .heightIn(min = 64.dp) .padding(16.dp), verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier .size(48.dp) .clip(CircleShape) .background(Color.LightGray.copy(alpha = alpha)) ) Spacer(modifier = Modifier.width(16.dp)) Box( modifier = Modifier .fillMaxWidth() .height(32.dp) .background(Color.LightGray.copy(alpha = alpha)) ) }
/** * The modified element can be horizontally swiped away. * * @param onDismissed Called when the element is swiped to the edge of the screen. */ private fun Modifier.swipeToDismiss( onDismissed: () -> Unit ): Modifier = composed { // This `Animatable` stores the horizontal offset for the element. val offsetX = remember { Animatable(0f) } pointerInput(Unit) { // Used to calculate a settling position of a fling animation. val decay = splineBasedDecay<Float>(this) // Wrap in a coroutine scope to use suspend functions for touch events and animation. coroutineScope { while (true) { // Wait for a touch down event. val pointerId = awaitPointerEventScope { awaitFirstDown().id } // Interrupt any ongoing animation. offsetX.stop() // Prepare for drag events and record velocity of a fling. val velocityTracker = VelocityTracker() // Wait for drag events. awaitPointerEventScope { horizontalDrag(pointerId) { change -> // Record the position after offset val horizontalDragOffset = offsetX.value + change.positionChange().x launch { // Overwrite the `Animatable` value while the element is dragged. offsetX.snapTo(horizontalDragOffset) } // Record the velocity of the drag. velocityTracker.addPosition(change.uptimeMillis, change.position) // Consume the gesture event, not passed to external change.consumePositionChange() } } // Dragging finished. Calculate the velocity of the fling. val velocity = velocityTracker.calculateVelocity().x // Calculate where the element eventually settles after the fling animation. val targetOffsetX = decay.calculateTargetValue(offsetX.value, velocity) // The animation should end as soon as it reaches these bounds. offsetX.updateBounds( lowerBound = -size.width.toFloat(), upperBound = size.width.toFloat() ) launch { if (targetOffsetX.absoluteValue <= size.width) { // Not enough velocity; Slide back to the default position. offsetX.animateTo(targetValue = 0f, initialVelocity = velocity) } else { // Enough velocity to slide away the element to the edge. offsetX.animateDecay(velocity, decay) // The element was swiped away. onDismissed() } } } } } // Apply the horizontal offset to the element. .offset { IntOffset(offsetX.value.roundToInt(), 0) } }