Jetpack Compose中ExoPlayer在网格布局下相邻视频重叠溢出的问题求助
Jetpack Compose中ExoPlayer在网格布局下相邻视频重叠溢出的问题求助
各位大佬好!之前提过类似的问题还没解决,现在补充细节再来求助,实在是踩坑踩得没辙了😭
我的Android应用用Jetpack Compose做了个媒体网格,每个格子里可能是图片或者视频。现在遇到个奇怪的问题:在3个项的网格里,第1和第3个是视频,中间那个竖屏视频居然直接突破父容器的边界,重叠到左边第一个视频的区域里了!我试过给视频、容器加各种布局约束,比如clipToBounds()、固定宽高、强制aspectRatio,全都没用。
后来我发现这个问题只在两个ExoPlayer实例相邻的时候才会触发:比如在4个项的网格里,第4个是竖屏视频,它上面的项是图片,这个视频就规规矩矩待在自己的容器里,完全不会溢出。
下面是我相关的代码片段,大家帮忙看看哪里出问题了:
MediaPreviewGrid 组件
@Composable fun MediaPreviewGrid( mediaItems: List<MimeiFileType>, viewModel: TweetViewModel, onFullScreenVideo: ((String, MimeiId) -> Unit)? = null, // Callback for full-screen video ) { val tweet by viewModel.tweetState.collectAsState() val navController = LocalNavController.current val maxItems = when (mediaItems.size) { 1 -> 1 2, 3 -> mediaItems.size else -> 4 } // Set up sequential playback for multiple videos val videoMids = remember { limitedMediaList.mapIndexedNotNull { index, item -> if (inferMediaTypeFromAttachment(item) == MediaType.Video) item.mid else null } } Box( modifier = Modifier .fillMaxWidth() .wrapContentWidth(Alignment.CenterHorizontally) ) { when (limitedMediaList.size) { 1 -> { val aspectRatio = if (aspectRatioOf(limitedMediaList[0]) > 0.8f) { aspectRatioOf(limitedMediaList[0]) } else { 0.8f } MediaItemView( limitedMediaList, modifier = Modifier .fillMaxWidth() .aspectRatio(aspectRatio) .clipToBounds() .clickable { val params = MediaViewerParams( mediaItems.map { MediaItem( getMediaUrl(it.mid, tweet.author?.baseUrl.orEmpty()).toString(), it.type ) }, 0, tweet.mid, tweet.authorId ) navController.navigate(NavTweet.MediaViewer(params)) }, index = 0, numOfHiddenItems = if (mediaItems.size > maxItems) mediaItems.size - maxItems else 0, autoPlay = firstVideoIndex == 0, inPreviewGrid = true, viewModel = viewModel, onFullScreenVideo = onFullScreenVideo ) } 2 -> {} 3 -> {} 4 -> {} } } }
MediaItemView 组件
@Composable fun MediaItemView( mediaItems: List<MimeiFileType>, modifier: Modifier = Modifier, index: Int, numOfHiddenItems: Int = 0, // add a PLUS sign to indicate more items not shown autoPlay: Boolean = false, // autoplay first video item, index 0 inPreviewGrid: Boolean = true, // use real aspectRatio when not displaying in preview grid. viewModel: TweetViewModel, onFullScreenVideo: ((String, MimeiId) -> Unit)? = null // Callback for full-screen video ) { val tweet by viewModel.tweetState.collectAsState() val attachments = mediaItems.map { val inferredType = inferMediaTypeFromAttachment(it) val mediaUrl = getMediaUrl(it.mid, tweet.author?.baseUrl.orEmpty()).toString() MediaItem(mediaUrl, inferredType) } val attachment = attachments[index] val navController = LocalNavController.current Box( modifier = modifier .background(Color.Gray.copy(alpha = 0.1f)) .clipToBounds(), contentAlignment = Alignment.Center ) { when (attachment.type) { MediaType.Image -> { // Use a Box with clickable modifier to handle image clicks Box( modifier = modifier .clipToBounds() .clickable { goto(index) } ) { ImageViewer( attachment.url, modifier = Modifier.fillMaxSize(), enableLongPress = false // Disable long press to allow clickable to work ) } } MediaType.Video -> { VideoPreview( url = attachment.url, modifier = modifier, index = index, autoPlay = autoPlay, inPreviewGrid = inPreviewGrid, aspectRatio = mediaItems[index].aspectRatio, callback = { goto(index) }, videoMid = mediaItems[index].mid ) } MediaType.Audio -> { val backgroundModifier = if (index % 2 != 0) { // Check if index is odd modifier.background(Color.Black.copy(alpha = 0.05f)) // Slightly darker background } else { modifier } Box( modifier = backgroundModifier .clipToBounds() .clickable { goto(index) } ) { AudioPreview(mediaItems, index, Modifier.fillMaxSize(), tweet) } } else -> { // add link to download other file type BlobLink(mediaItems[index], attachment.url, modifier) } } if (numOfHiddenItems > 0) { /** * Show a PLUS sign and number to indicate more items not shown * */ Box( modifier = Modifier .matchParentSize() .background(Color(0x40FFFFFF)), // Lighter shaded background contentAlignment = Alignment.Center ) { Row(modifier = Modifier.align(Alignment.Center)) { Icon( imageVector = Icons.Outlined.Add, contentDescription = null, tint = Color.White, modifier = Modifier .size(50.dp) .alpha(0.8f) ) Text( text = numOfHiddenItems.toString(), color = Color.White, fontSize = 50.sp, // Adjust this value as needed textAlign = TextAlign.Center, modifier = Modifier .alpha(0.8f) ) } } } } }
VideoPreview 组件(核心ExoPlayer封装)
@Composable fun VideoPreview( url: String, modifier: Modifier, index: Int, autoPlay: Boolean = false, inPreviewGrid: Boolean = true, aspectRatio: Float?, callback: (Int) -> Unit, videoMid: MimeiId ) { // 这里是ExoPlayer的Compose封装实现,比如使用PlayerView配合AndroidView // 核心逻辑是初始化ExoPlayer并加载视频资源 }
我现在的猜测是,ExoPlayer的底层View可能绕过了Compose的布局约束?或者是多个Player实例之间有什么层级冲突?有没有大佬遇到过类似的情况,给点思路或者解决方案吧,实在是卡在这里好久了🙏
内容来源于stack exchange
相关产品推荐
相关产品推荐

