Я задал аналогичный вопрос, который нерешен. Я снова спрашиваю с дополнительной информацией. В моем приложении Android есть сетка, состоящий из элементов сетки, которые могут быть видео или изображением. В следующей сетке из 3 предметов. Первый и третий - видео. Ориентация 2 -го видео - портрет, и оно переполняется от границы своего родительского контейнера в первое видео. пользоваться Я обнаружил, что это происходит только тогда, когда два экзоплареи перекрывают друг друга. В следующей сетке 4 -й пункт также является портретным видео. Элемент выше - это изображение, а видео -белоты он остается в своем контейнере.@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
}
}
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 -> {}
}
}
}
@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)
)
}
}
}
}
}
< /code>
@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)
}
val exoPlayer = remember(url, videoMid) {
if (videoMid != null) {
VideoManager.getVideoPlayer(context, videoMid, url)
} else {
createExoPlayer(context, url, MediaType.Video)
}
}
// Preload video if not already cached
Box(
modifier = modifier
.clipToBounds()
.background(MaterialTheme.colorScheme.surfaceVariant) // Material3 surface variant for loading background
.onGloballyPositioned { layoutCoordinates ->
isVideoVisible = isElementVisible(layoutCoordinates)
}
.clickable {
// Auto-start video in full screen
callback(index)
}
) {
AndroidView(
factory = {
PlayerView(context).apply {
player = exoPlayer
useController = false // No controls in preview mode
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
// Set background color to light gray (Material3 surface variant equivalent)
setBackgroundColor(android.graphics.Color.rgb(245, 245, 245))
// Show buffering indicator
setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
}
},
modifier = Modifier.fillMaxWidth()
)
// Show loading indicator when video is loading
if (isLoading) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = androidx.compose.ui.Alignment.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(32.dp),
color = MaterialTheme.colorScheme.primary
)
}
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/797 ... each-other
Содержание экзоплал, перекрывающих друг друга ⇐ Android
Форум для тех, кто программирует под Android
-
Anonymous
1757908288
Anonymous
Я задал аналогичный вопрос, который нерешен. Я снова спрашиваю с дополнительной информацией. В моем приложении Android есть сетка, состоящий из элементов сетки, которые могут быть видео или изображением. В следующей сетке из 3 предметов. Первый и третий - видео. Ориентация 2 -го видео - портрет, и оно переполняется от границы своего родительского контейнера в первое видео. пользоваться Я обнаружил, что это происходит только тогда, когда два экзоплареи перекрывают друг друга. В следующей сетке 4 -й пункт также является портретным видео. Элемент выше - это изображение, а видео -белоты он остается в своем контейнере.@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
}
}
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 -> {}
}
}
}
@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)
)
}
}
}
}
}
< /code>
@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)
}
val exoPlayer = remember(url, videoMid) {
if (videoMid != null) {
VideoManager.getVideoPlayer(context, videoMid, url)
} else {
createExoPlayer(context, url, MediaType.Video)
}
}
// Preload video if not already cached
Box(
modifier = modifier
.clipToBounds()
.background(MaterialTheme.colorScheme.surfaceVariant) // Material3 surface variant for loading background
.onGloballyPositioned { layoutCoordinates ->
isVideoVisible = isElementVisible(layoutCoordinates)
}
.clickable {
// Auto-start video in full screen
callback(index)
}
) {
AndroidView(
factory = {
PlayerView(context).apply {
player = exoPlayer
useController = false // No controls in preview mode
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
// Set background color to light gray (Material3 surface variant equivalent)
setBackgroundColor(android.graphics.Color.rgb(245, 245, 245))
// Show buffering indicator
setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
}
},
modifier = Modifier.fillMaxWidth()
)
// Show loading indicator when video is loading
if (isLoading) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = androidx.compose.ui.Alignment.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(32.dp),
color = MaterialTheme.colorScheme.primary
)
}
}
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79718049/content-of-exoplayers-overlapping-each-other[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия