Ich arbeite an einer Twitter -ähnlichen App und verwende Jetpack Compose und ExoPlayer3. In meiner Android -App gibt es eine Netzansicht, die aus Gitterartikeln besteht, die ein Video oder ein Bild sein können. Im Folgenden von 3 Elementen. Der erste und der 3. sind Videos. Die Ausrichtung des 2. Videos ist Porträt und überläuft den Rand des übergeordneten Containers in das erste Video. Ich stellte fest, dass es nur dann passiert, wenn sich zwei Exoplayer gegenseitig überlappen. Im folgenden Raster ist der 4. Element auch ein Porträtvideo. Das Element oben ist ein Bild und das Video belastet es in seinem Container fein.
Ich arbeite an einer Twitter -ähnlichen App und verwende Jetpack Compose und ExoPlayer3. In meiner Android -App gibt es eine Netzansicht, die aus Gitterartikeln besteht, die ein Video oder ein Bild sein können. Im Folgenden von 3 Elementen. Der erste und der 3. sind Videos. Die Ausrichtung des 2. Videos ist Porträt und überläuft den Rand des übergeordneten Containers in das erste Video. Ich stellte fest, dass es nur dann passiert, wenn sich zwei Exoplayer gegenseitig überlappen. Im folgenden Raster ist der 4. Element auch ein Porträtvideo. Das Element oben ist ein Bild und das Video belastet es in seinem Container fein.[code]@Composable fun MediaPreviewGrid( mediaItems: List, 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 } }
@Composable fun MediaItemView( mediaItems: List, 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) ) } } } } }
@Composable fun VideoPreview( url: String, modifier: Modifier, index: Int, autoPlay: Boolean = false, inPreviewGrid: Boolean = true, aspectRatio: Float?, callback: (Int) -> Unit, videoMid: MimeiId? = null ) { val context = LocalContext.current var isVideoVisible by remember { mutableStateOf(false) } var isMuted by remember { mutableStateOf(preferenceHelper.getSpeakerMute()) } var isLoading by remember { mutableStateOf(videoMid?.let { !VideoManager.isVideoPreloaded(it) } ?: true) }
Ich habe ein vorhandenes Projekt in Android Studio wieder aufgebaut, und der folgende Fehler tritt auf
1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task...
Ich habe ein vorhandenes Projekt in Android Studio wieder aufgebaut, und der folgende Fehler tritt auf
1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task...
Ich stehe vor einem Problem, bei dem die PlayerView von ExoPlayer nach dem Zurücknavigieren ausläuft oder auf den vorherigen Bildschirm überspringt. Dies geschieht, wenn ich die Zurück-Taste drücke...
Ich erstelle einen Videoplayer mit dem neuesten Media3 -Exoplayer mit Jetpack Compose:
Das Problem, mit dem ich ausgesetzt bin AndroidView(modifier = Modifier.fillMaxSize(),...)