Compose 动画 AnimatedVisibility
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) } }