我有 2 个屏幕,里面有 videoview,我使用 accompanist-navigation-animation 库在它们之间进行转换。两个组成“屏幕”之间的转换很慢,我认为这可能与我如何开始视频有关,但我无法弄清楚。此外,当从第一个屏幕转换到第二个屏幕时,重新组合会运行多次。有更多知识的人可以看看我如何处理视频播放。
@ExperimentalAnimationApi
@Composable
fun Navigation() {
val navController = rememberAnimatedNavController()
val activity = (LocalContext.current as? Activity)
AnimatedNavHost(
navController = navController,
startDestination = "promoScreen1"
) {
composable("promoScreen1",
exitTransition = {
slideOutOfContainer(
AnimatedContentScope.SlideDirection.Left,
animationSpec = tween(1000)
)
}
) {
val repeatsPromoViewModel: RepeatsPromoViewModel = viewModel()
RepeatsPromoScreen(
repeatsPromoViewModel = viewModel(),
navController = navController,
videoFileName = "repeat_promo1",
title = stringResource(id = R.string.repeats_promo_title1),
subtitle = stringResource(id = R.string.repeats_promo_subtitle),
description = stringResource(id = R.string.repeats_promo_description),
bottomButtonText = stringResource(id = R.string.next).uppercase(),
onBottomButtonClicked = {
repeatsPromoViewModel._overlayVisible.value = true
repeatsPromoViewModel.isPlaying.value = false
navController.navigate("promoScreen2")
}
)
}
composable("promoScreen2", enterTransition = {
slideIntoContainer(
AnimatedContentScope.SlideDirection.Left,
animationSpec = tween(1000)
)
}) {
val repeatsPromoViewModel: RepeatsPromoViewModel = viewModel()
BackHandler(true) {} //disable back button
RepeatsPromoScreen(
repeatsPromoViewModel = repeatsPromoViewModel,
navController = navController,
videoFileName = "repeat_promo2",
title = stringResource(id = R.string.repeats_promo_title2),
subtitle = stringResource(id = R.string.repeats_promo_subtitle2),
description = stringResource(id = R.string.repeats_promo_description2),
bottomButtonText = stringResource(id = R.string.planning_tutorial_finish).uppercase()
) { activity?.finish() }
}
}
}
@ExperimentalAnimationApi
@Composable
fun RepeatsPromoScreen(
repeatsPromoViewModel: RepeatsPromoViewModel,
navController: NavController,
videoFileName: String,
title: String,
subtitle: String,
description: String,
bottomButtonText: String,
onBottomButtonClicked: () -> Unit
) {
val activity = (LocalContext.current as? Activity)
val overlayVisible by repeatsPromoViewModel.overlayVisible
val configuration = LocalConfiguration.current
val isSmallScreen = configuration.screenHeightDp < 720 || configuration.screenWidthDp <= 360
var modifier = Modifier
.fillMaxSize()
.background(color = Color(0xFFEBF4F9))
if (isSmallScreen) {
modifier =
modifier.then(Modifier.verticalScroll(rememberScrollState())) //enable scrolling on small screens
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
Box(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.Start)
) {
IconButton(
onClick = { activity?.finish() }
) {
Icon(
Icons.Filled.Close,
contentDescription = "Close screen"
)
}
}
Text(
text = title,
fontSize = 28.sp,
lineHeight = 22.sp,
textAlign = TextAlign.Center,
fontFamily = FontFamily(Font(R.font.source_serif_pro_black)),
modifier = Modifier.padding(top = 24.dp),
color = colorResource(id = R.color.toshl_profile_name)
)
Text(
text = subtitle,
fontSize = 14.sp,
lineHeight = 17.sp,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 10.dp, start = 50.dp, end = 50.dp),
color = colorResource(id = R.color.toshl_sync_subtitle)
)
val rawId =
activity?.resources?.getIdentifier(videoFileName, "raw", activity.packageName)
val path = "android.resource://" + activity?.packageName + "/" + rawId
val retriever = MediaMetadataRetriever()
retriever.setDataSource(activity, Uri.parse(path))
val frame = retriever.frameAtTime
val videoWidth = frame?.width?.toFloat() ?: 0.toFloat()
val videoHeight = frame?.height?.toFloat() ?: 0.toFloat()
val ratio = configuration.screenWidthDp / UiHelper.convertPxToDp(
activity!!.applicationContext,
videoWidth
)
val videoView = remember(activity) {
VideoView(activity).apply {
setVideoPath(path)
setOnPreparedListener { mp: MediaPlayer ->
mp.setOnInfoListener(MediaPlayer.OnInfoListener { mp, what, _ ->
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
repeatsPromoViewModel._overlayVisible.value = false
return@OnInfoListener true
}
false
})
mp.start()
mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING)
mp.isLooping = true
}
}
}
val videoContainerHeight =
UiHelper.convertPxToDp(activity.applicationContext, videoHeight) * ratio
Box() {
AndroidView(
modifier = Modifier
.padding(top = 25.dp, start = 0.dp, end = 0.dp)
.height(videoContainerHeight.dp),
factory = { context ->
videoView
}
)
//overlay
this@Column.AnimatedVisibility(visible = overlayVisible) {
Box(
modifier = Modifier
.padding(top = 25.dp, start = 0.dp, end = 0.dp)
.height(videoContainerHeight.dp)
.background(Color(0xFFEBF4F9))
.clip(RectangleShape)
.fillMaxSize()
)
}
}
Text(
text = description,
fontSize = 14.sp,
lineHeight = 17.sp,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 30.dp, start = 50.dp, end = 50.dp),
color = colorResource(id = R.color.toshl_sync_subtitle)
)
if (isSmallScreen) { //just add button below other elements
PromoBottomButton(
paddingTop = 32.dp,
paddingBottom = 16.dp,
onFinishClicked = { },
text = stringResource(id = R.string.next).uppercase()
)
} else { //pin button to bottom of screen (that's why its wrapped inside another column)
Column(
modifier = Modifier
.fillMaxSize()
.align(Alignment.CenterHorizontally),
verticalArrangement = Arrangement.Bottom
) {
PromoBottomButton(
paddingTop = 16.dp,
paddingBottom = 32.dp,
onFinishClicked = { onBottomButtonClicked.invoke() },
text = bottomButtonText
)
}
}
}
}