У меня есть пользовательский композитный видеороскретен, созданный в моем приложении. Проблема, которая у меня возникает, заключается в том, что когда я перехожу от экрана отключения обратно на экран процедуры, на котором отображается композитный VideoScReen, появляется странная анимация при повторном появлении экрана. Почему это происходит и как это исправить. > < /p>
@Composable
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
internal fun VideoScreen(
shouldPause: Boolean = false,
videoUrl: String?,
currentTime: Duration = Duration.ZERO,
onPlaybackTimeUpdate: (current: Duration, total: Duration) -> Unit = { _, _ -> },
onVideoEnd: (total: Duration) -> Unit = {},
isInLoopMode: Boolean = false,
videoHeightFraction: Float? = null,
videoResizeMode: Int = AspectRatioFrameLayout.RESIZE_MODE_ZOOM,
seekToCurrentTimeWhenChanged: Boolean = false,
videoOffsetProvider: (() -> IntOffset)? = null,
autoPausePlayPlaybackOnLifecycleEvents: Boolean = true,
onClick: (() -> Unit)? = null,
) {
val context = LocalContext.current
val activity = context as Activity
val configuration = LocalConfiguration.current
val heightFraction = remember {
derivedStateOf {
when (configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> 1f
else -> videoHeightFraction
}
}
}
var isPlaying by remember { mutableStateOf(false) }
var isVideoOver by remember { mutableStateOf(false) }
val exoPlayer = remember { ExoPlayer.Builder(context).build() }
ExoPlayerLifecycleDisposableEffect(
getExoPlayer = { exoPlayer },
autoPausePlayPlaybackOnLifecycleEvents = autoPausePlayPlaybackOnLifecycleEvents,
)
SetupExoPlayerEffect(
videoUrl = videoUrl,
exoPlayer = exoPlayer,
currentTime = currentTime,
shouldPause = shouldPause,
isInLoopMode = isInLoopMode,
seekToCurrentTimeWhenChanged = seekToCurrentTimeWhenChanged,
autoPausePlayPlaybackOnLifecycleEvents = autoPausePlayPlaybackOnLifecycleEvents,
)
SetupExoPlayerListenersDisposableEffect(
exoPlayer = exoPlayer,
setIsPlaying = { isPlaying = it },
setIsVideoOver = { isVideoOver = it },
)
if (isPlaying || isVideoOver) {
LaunchedEffect(Unit) {
while (isPlaying) {
activity.keepDeviceAwake(keepAwake = true)
onPlaybackTimeUpdate(
exoPlayer.currentPosition.milliseconds,
exoPlayer.duration.milliseconds,
)
delay(1000)
}
if (isVideoOver) {
activity.keepDeviceAwake(keepAwake = false)
onVideoEnd(exoPlayer.duration.milliseconds)
}
}
}
LaunchedEffect(key1 = shouldPause) {
activity.keepDeviceAwake(keepAwake = !shouldPause)
exoPlayer.playWhenReady = !shouldPause
}
// Implementing ExoPlayer
AndroidView(
factory = {
PlayerView(context).apply {
// this will ignore video aspect ratio
resizeMode = videoResizeMode
player = exoPlayer
useController = false
}
},
modifier = Modifier
.offset { videoOffsetProvider?.invoke() ?: IntOffset(0, 0) }
.then(
// don't change height otherwise as it can result in stretched video
heightFraction.value?.let {
Modifier.fillMaxHeight(it)
} ?: Modifier,
)
.fillMaxWidth()
.background(Color.Black)
.then(
if (onClick != null) {
Modifier.noRippleClickable(onClick)
} else {
Modifier
},
),
)
}
@Composable
private fun SetupExoPlayerEffect(
videoUrl: String?,
exoPlayer: ExoPlayer,
currentTime: Duration,
shouldPause: Boolean,
isInLoopMode: Boolean,
seekToCurrentTimeWhenChanged: Boolean,
autoPausePlayPlaybackOnLifecycleEvents: Boolean,
) {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(videoUrl) {
val observer = LifecycleEventObserver { _, event ->
if (event != Lifecycle.Event.ON_RESUME) {
return@LifecycleEventObserver
}
videoUrl ?: return@LifecycleEventObserver
if (!autoPausePlayPlaybackOnLifecycleEvents &&
exoPlayer.currentMediaItem?.mediaId == videoUrl
) {
return@LifecycleEventObserver
}
val mediaItem = MediaItem.fromUri(videoUrl)
.buildUpon()
.setMediaId(videoUrl)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.seekToIfNeeded(currentTime)
exoPlayer.playWhenReady = !shouldPause
exoPlayer.repeatMode = if (isInLoopMode) {
Player.REPEAT_MODE_ALL
} else {
Player.REPEAT_MODE_OFF
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
if (seekToCurrentTimeWhenChanged) {
LaunchedEffect(currentTime) {
exoPlayer.seekToIfNeeded(currentTime)
}
}
}
@Composable
private fun ExoPlayerLifecycleDisposableEffect(
getExoPlayer: () -> ExoPlayer?,
autoPausePlayPlaybackOnLifecycleEvents: Boolean,
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val player = getExoPlayer()
DisposableEffect(context) {
val observer = LifecycleEventObserver { _, event ->
if (!autoPausePlayPlaybackOnLifecycleEvents) {
return@LifecycleEventObserver
}
when (event) {
Lifecycle.Event.ON_PAUSE ->
player?.pause()
Lifecycle.Event.ON_RESUME ->
player?.play()
Lifecycle.Event.ON_STOP ->
player?.stop()
else -> {}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
player?.release()
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}
@Composable
private fun SetupExoPlayerListenersDisposableEffect(
exoPlayer: ExoPlayer?,
setIsPlaying: (isPlaying: Boolean) -> Unit,
setIsVideoOver: (isPlaying: Boolean) -> Unit,
) {
exoPlayer ?: return
DisposableEffect(exoPlayer) {
val playerListener = object : Player.Listener {
override fun onIsPlayingChanged(playing: Boolean) {
setIsPlaying(playing)
}
override fun onPlaybackStateChanged(playbackState: Int) {
setIsVideoOver(playbackState == Player.STATE_ENDED)
}
}
exoPlayer.addListener(playerListener)
onDispose {
exoPlayer.removeListener(playerListener)
exoPlayer.release()
}
}
}
private fun ExoPlayer.seekToIfNeeded(position: Duration) {
if (position
Box(modifier = Modifier.fillMaxSize()) {
if (screenState.screenState == PowerBasedDeviceScreenState.ScreenState.END) {
Image(
modifier = Modifier
.fillMaxHeight(0.4f)
.fillMaxWidth(),
painter = rememberAsyncImagePainter(routineDetailsState.unwrap()?.currentExercise?.imageUrl),
contentDescription = null,
contentScale = ContentScale.Crop,
)
} else {
VideoScreen(
shouldPause = screenState.isPaused,
currentTime = screenState.currentVideoProgress,
videoUrl = screenState.videoUrl,
videoHeightFraction = 0.4f,
autoPausePlayPlaybackOnLifecycleEvents = false,
)
}
}
Подробнее здесь: https://stackoverflow.com/questions/794 ... -animation
JetPack Compose Android -видео Weird Animation ⇐ Android
Форум для тех, кто программирует под Android
-
Anonymous
1740389032
Anonymous
У меня есть пользовательский композитный видеороскретен, созданный в моем приложении. Проблема, которая у меня возникает, заключается в том, что когда я перехожу от экрана отключения обратно на экран процедуры, на котором отображается композитный VideoScReen, появляется странная анимация при повторном появлении экрана. Почему это происходит и как это исправить. > < /p>
@Composable
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
internal fun VideoScreen(
shouldPause: Boolean = false,
videoUrl: String?,
currentTime: Duration = Duration.ZERO,
onPlaybackTimeUpdate: (current: Duration, total: Duration) -> Unit = { _, _ -> },
onVideoEnd: (total: Duration) -> Unit = {},
isInLoopMode: Boolean = false,
videoHeightFraction: Float? = null,
videoResizeMode: Int = AspectRatioFrameLayout.RESIZE_MODE_ZOOM,
seekToCurrentTimeWhenChanged: Boolean = false,
videoOffsetProvider: (() -> IntOffset)? = null,
autoPausePlayPlaybackOnLifecycleEvents: Boolean = true,
onClick: (() -> Unit)? = null,
) {
val context = LocalContext.current
val activity = context as Activity
val configuration = LocalConfiguration.current
val heightFraction = remember {
derivedStateOf {
when (configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> 1f
else -> videoHeightFraction
}
}
}
var isPlaying by remember { mutableStateOf(false) }
var isVideoOver by remember { mutableStateOf(false) }
val exoPlayer = remember { ExoPlayer.Builder(context).build() }
ExoPlayerLifecycleDisposableEffect(
getExoPlayer = { exoPlayer },
autoPausePlayPlaybackOnLifecycleEvents = autoPausePlayPlaybackOnLifecycleEvents,
)
SetupExoPlayerEffect(
videoUrl = videoUrl,
exoPlayer = exoPlayer,
currentTime = currentTime,
shouldPause = shouldPause,
isInLoopMode = isInLoopMode,
seekToCurrentTimeWhenChanged = seekToCurrentTimeWhenChanged,
autoPausePlayPlaybackOnLifecycleEvents = autoPausePlayPlaybackOnLifecycleEvents,
)
SetupExoPlayerListenersDisposableEffect(
exoPlayer = exoPlayer,
setIsPlaying = { isPlaying = it },
setIsVideoOver = { isVideoOver = it },
)
if (isPlaying || isVideoOver) {
LaunchedEffect(Unit) {
while (isPlaying) {
activity.keepDeviceAwake(keepAwake = true)
onPlaybackTimeUpdate(
exoPlayer.currentPosition.milliseconds,
exoPlayer.duration.milliseconds,
)
delay(1000)
}
if (isVideoOver) {
activity.keepDeviceAwake(keepAwake = false)
onVideoEnd(exoPlayer.duration.milliseconds)
}
}
}
LaunchedEffect(key1 = shouldPause) {
activity.keepDeviceAwake(keepAwake = !shouldPause)
exoPlayer.playWhenReady = !shouldPause
}
// Implementing ExoPlayer
AndroidView(
factory = {
PlayerView(context).apply {
// this will ignore video aspect ratio
resizeMode = videoResizeMode
player = exoPlayer
useController = false
}
},
modifier = Modifier
.offset { videoOffsetProvider?.invoke() ?: IntOffset(0, 0) }
.then(
// don't change height otherwise as it can result in stretched video
heightFraction.value?.let {
Modifier.fillMaxHeight(it)
} ?: Modifier,
)
.fillMaxWidth()
.background(Color.Black)
.then(
if (onClick != null) {
Modifier.noRippleClickable(onClick)
} else {
Modifier
},
),
)
}
@Composable
private fun SetupExoPlayerEffect(
videoUrl: String?,
exoPlayer: ExoPlayer,
currentTime: Duration,
shouldPause: Boolean,
isInLoopMode: Boolean,
seekToCurrentTimeWhenChanged: Boolean,
autoPausePlayPlaybackOnLifecycleEvents: Boolean,
) {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(videoUrl) {
val observer = LifecycleEventObserver { _, event ->
if (event != Lifecycle.Event.ON_RESUME) {
return@LifecycleEventObserver
}
videoUrl ?: return@LifecycleEventObserver
if (!autoPausePlayPlaybackOnLifecycleEvents &&
exoPlayer.currentMediaItem?.mediaId == videoUrl
) {
return@LifecycleEventObserver
}
val mediaItem = MediaItem.fromUri(videoUrl)
.buildUpon()
.setMediaId(videoUrl)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.seekToIfNeeded(currentTime)
exoPlayer.playWhenReady = !shouldPause
exoPlayer.repeatMode = if (isInLoopMode) {
Player.REPEAT_MODE_ALL
} else {
Player.REPEAT_MODE_OFF
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
if (seekToCurrentTimeWhenChanged) {
LaunchedEffect(currentTime) {
exoPlayer.seekToIfNeeded(currentTime)
}
}
}
@Composable
private fun ExoPlayerLifecycleDisposableEffect(
getExoPlayer: () -> ExoPlayer?,
autoPausePlayPlaybackOnLifecycleEvents: Boolean,
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val player = getExoPlayer()
DisposableEffect(context) {
val observer = LifecycleEventObserver { _, event ->
if (!autoPausePlayPlaybackOnLifecycleEvents) {
return@LifecycleEventObserver
}
when (event) {
Lifecycle.Event.ON_PAUSE ->
player?.pause()
Lifecycle.Event.ON_RESUME ->
player?.play()
Lifecycle.Event.ON_STOP ->
player?.stop()
else -> {}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
player?.release()
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}
@Composable
private fun SetupExoPlayerListenersDisposableEffect(
exoPlayer: ExoPlayer?,
setIsPlaying: (isPlaying: Boolean) -> Unit,
setIsVideoOver: (isPlaying: Boolean) -> Unit,
) {
exoPlayer ?: return
DisposableEffect(exoPlayer) {
val playerListener = object : Player.Listener {
override fun onIsPlayingChanged(playing: Boolean) {
setIsPlaying(playing)
}
override fun onPlaybackStateChanged(playbackState: Int) {
setIsVideoOver(playbackState == Player.STATE_ENDED)
}
}
exoPlayer.addListener(playerListener)
onDispose {
exoPlayer.removeListener(playerListener)
exoPlayer.release()
}
}
}
private fun ExoPlayer.seekToIfNeeded(position: Duration) {
if (position
Box(modifier = Modifier.fillMaxSize()) {
if (screenState.screenState == PowerBasedDeviceScreenState.ScreenState.END) {
Image(
modifier = Modifier
.fillMaxHeight(0.4f)
.fillMaxWidth(),
painter = rememberAsyncImagePainter(routineDetailsState.unwrap()?.currentExercise?.imageUrl),
contentDescription = null,
contentScale = ContentScale.Crop,
)
} else {
VideoScreen(
shouldPause = screenState.isPaused,
currentTime = screenState.currentVideoProgress,
videoUrl = screenState.videoUrl,
videoHeightFraction = 0.4f,
autoPausePlayPlaybackOnLifecycleEvents = false,
)
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79462911/jetpack-compose-android-video-weird-animation[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия