Exo Player动画失效:点击按钮后无法实现平滑显隐过渡
解决ExoPlayer在Compose中淡入淡出动画失效的问题
问题出在AnimatedVisibility会直接添加/移除Compose组件,而你用AndroidView包裹的PlayerView是原生View,Compose在处理原生View的移除时会直接从父布局中删除,导致exit动画被中断,看不到渐变效果;淡入时同理,原生View突然被添加,动画无法生效。
下面是两种可行的解决方案:
方案一:使用透明度动画控制(推荐)
通过animateFloatAsState控制透明度,不直接移除PlayerView组件,只是改变其透明度,这样原生View不会被销毁/添加,动画能正常执行:
@Composable fun TestPlayerScreen( modifier: Modifier = Modifier, ) { val context = LocalContext.current val exoPlayer = remember { ExoPlayer.Builder(context).build() } val mediaSource = remember { MediaItem.Builder() .setUri("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4") .build() } var showPlayer by remember { mutableStateOf(true) } // 控制透明度的动画状态 val alpha by animateFloatAsState( targetValue = if (showPlayer) 1f else 0f, animationSpec = tween(5000), label = "playerAlpha" ) DisposableEffect(mediaSource) { exoPlayer.setMediaItem(mediaSource) exoPlayer.prepare() onDispose { exoPlayer.release() } } Column { Box( modifier = modifier .width(300.dp) .height(200.dp) .alpha(alpha) // 透明度为0时禁止交互,避免误触 .pointerInput(alpha) { if (alpha == 0f) { awaitPointerEventScope { awaitPointerEvent() } } } ) { AndroidView( factory = { ctx -> PlayerView(ctx).apply { player = exoPlayer } } ) } Button(onClick = { showPlayer = !showPlayer }) { Text("Show/Hide player") } } }
方案二:用Transition API管理动画状态
通过updateTransition统一管理显示状态和动画,同时在动画结束后控制布局高度,避免占用多余空间:
@Composable fun TestPlayerScreen( modifier: Modifier = Modifier, ) { val context = LocalContext.current val exoPlayer = remember { ExoPlayer.Builder(context).build() } val mediaSource = remember { MediaItem.Builder() .setUri("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4") .build() } var showPlayer by remember { mutableStateOf(true) } // 创建过渡状态管理 val transition = updateTransition(showPlayer, label = "playerTransition") val alpha by transition.animateFloat( transitionSpec = { tween(5000) }, label = "playerAlpha" ) { visible -> if (visible) 1f else 0f } DisposableEffect(mediaSource) { exoPlayer.setMediaItem(mediaSource) exoPlayer.prepare() onDispose { exoPlayer.release() } } Column { Box( modifier = modifier .width(300.dp) .alpha(alpha) // 动画结束后隐藏布局高度 .height(if (showPlayer || alpha > 0f) 200.dp else 0.dp) ) { AndroidView( factory = { ctx -> PlayerView(ctx).apply { player = exoPlayer } } ) } Button(onClick = { showPlayer = !showPlayer }) { Text("Show/Hide player") } } }
核心思路
AnimatedVisibility的问题在于它会触发组件的添加/移除,而原生View无法在这个过程中正确执行Compose的动画逻辑。改用透明度动画后,PlayerView始终存在于布局中,只是通过透明度变化实现显示/隐藏,完美适配原生View的生命周期。
内容的提问来源于stack exchange,提问作者Rodion
相关产品推荐
相关产品推荐

