JetPack Compose-超级盖子全屏

发布于 2025-01-25 19:55:44 字数 2069 浏览 3 评论 0原文

我正在尝试在用JetPack Compose制造的Android应用中蒸展视频。要流媒体播放我,但我真的不明白如何实现全屏按钮,一些建议?

@Composable
private fun VideoPlayer() {
    val videoURI = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    val httpDataSourceFactory: HttpDataSource.Factory =
        DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(false)
    val dataSourceFactory: DataSource.Factory = DataSource.Factory {
        val dataSource = httpDataSourceFactory.createDataSource()
        dataSource.setRequestProperty(
            "cookie", "cookieValue"
        )
        dataSource.setRequestProperty("Range", "1-10000")
        dataSource
    }

    val mContext = LocalContext.current
    // Initializing ExoPLayer
    val mExoPlayer = remember(mContext) {
        ExoPlayer.Builder(mContext)
            .setMediaSourceFactory(DefaultMediaSourceFactory(dataSourceFactory)).build().apply {

                val mediaItem = MediaItem.Builder()
                    .setUri(Uri.parse(videoURI))
                    .build()
                setMediaItem(mediaItem)
                playWhenReady = true
                prepare()

            }

    }

    DisposableEffect(

        // Implementing ExoPlayer
        AndroidView(factory = { context ->
            StyledPlayerView(context).apply {
                player = mExoPlayer
            }
        })
    ) {
        onDispose {
            mExoPlayer.release()
        }
    }
}

编辑 添加setControlleronfullscreenmodechangedlistener props exo将显示全屏的构建按钮,我解决了我的问题,呼叫此listner中的全屏幕功能

            AndroidView(
                factory = { context ->
                    StyledPlayerView(context).apply {
                        player = mExoPlayer
                        setControllerOnFullScreenModeChangedListener {
                        if(it)
                            //fullscreen
                        else
                            //minimize
                    }                    }
                })

i am trying to steam a video in my android app made with jetpack compose. To stream i using ExoPlayer but i can't really understand how to implement a full screen button, some advice?

@Composable
private fun VideoPlayer() {
    val videoURI = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    val httpDataSourceFactory: HttpDataSource.Factory =
        DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(false)
    val dataSourceFactory: DataSource.Factory = DataSource.Factory {
        val dataSource = httpDataSourceFactory.createDataSource()
        dataSource.setRequestProperty(
            "cookie", "cookieValue"
        )
        dataSource.setRequestProperty("Range", "1-10000")
        dataSource
    }

    val mContext = LocalContext.current
    // Initializing ExoPLayer
    val mExoPlayer = remember(mContext) {
        ExoPlayer.Builder(mContext)
            .setMediaSourceFactory(DefaultMediaSourceFactory(dataSourceFactory)).build().apply {

                val mediaItem = MediaItem.Builder()
                    .setUri(Uri.parse(videoURI))
                    .build()
                setMediaItem(mediaItem)
                playWhenReady = true
                prepare()

            }

    }

    DisposableEffect(

        // Implementing ExoPlayer
        AndroidView(factory = { context ->
            StyledPlayerView(context).apply {
                player = mExoPlayer
            }
        })
    ) {
        onDispose {
            mExoPlayer.release()
        }
    }
}

Edit
Adding the setControllerOnFullScreenModeChangedListener props exo will show a build in button for the fullscreen, i solved my problem calling the full screen function inside this listner

            AndroidView(
                factory = { context ->
                    StyledPlayerView(context).apply {
                        player = mExoPlayer
                        setControllerOnFullScreenModeChangedListener {
                        if(it)
                            //fullscreen
                        else
                            //minimize
                    }                    }
                })

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

断爱 2025-02-01 19:55:44

使用此代码

AndroidView(factory = {
        StyledPlayerView(context).apply {
            player = exoPlayer
            setFullscreenButtonClickListener { isFullScreen ->
                with(context) {
                    if (isFullScreen) {
                         setScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
                    } else {
                         setScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
                    }
                }
            }
      }
})

使用此扩展功能查找活动实例:

fun Context.findActivity(): Activity? = when (this) {
    is Activity       -> this
    is ContextWrapper -> baseContext.findActivity()
    else              -> null
}

设置屏幕方向使用以下扩展功能:

fun Context.setScreenOrientation(orientation: Int) {
    val activity = this.findActivity() ?: return
    activity.requestedOrientation = orientation
    if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
       hideSystemUi()
    } else {
       showSystemUi()
    }
}

最后将此功能用于hide/show system ui(状态栏):

fun Context.hideSystemUi() {
    val activity = this.findActivity() ?: return
    val window = activity.window ?: return
    WindowCompat.setDecorFitsSystemWindows(window, false)
    WindowInsetsControllerCompat(window, window.decorView).let { controller ->
    controller.hide(WindowInsetsCompat.Type.systemBars())
    controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
   }
}

fun Context.showSystemUi() {
    val activity = this.findActivity() ?: return
    val window = activity.window ?: return
    WindowCompat.setDecorFitsSystemWindows(window, true)
   WindowInsetsControllerCompat(
    window,
    window.decorView
   ).show(WindowInsetsCompat.Type.systemBars())
}

use this code

AndroidView(factory = {
        StyledPlayerView(context).apply {
            player = exoPlayer
            setFullscreenButtonClickListener { isFullScreen ->
                with(context) {
                    if (isFullScreen) {
                         setScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
                    } else {
                         setScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
                    }
                }
            }
      }
})

use this extension function for find activity instance:

fun Context.findActivity(): Activity? = when (this) {
    is Activity       -> this
    is ContextWrapper -> baseContext.findActivity()
    else              -> null
}

to set screen orientation use below extension function:

fun Context.setScreenOrientation(orientation: Int) {
    val activity = this.findActivity() ?: return
    activity.requestedOrientation = orientation
    if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
       hideSystemUi()
    } else {
       showSystemUi()
    }
}

and finally use this functions for hide/show system ui (status bar):

fun Context.hideSystemUi() {
    val activity = this.findActivity() ?: return
    val window = activity.window ?: return
    WindowCompat.setDecorFitsSystemWindows(window, false)
    WindowInsetsControllerCompat(window, window.decorView).let { controller ->
    controller.hide(WindowInsetsCompat.Type.systemBars())
    controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
   }
}

fun Context.showSystemUi() {
    val activity = this.findActivity() ?: return
    val window = activity.window ?: return
    WindowCompat.setDecorFitsSystemWindows(window, true)
   WindowInsetsControllerCompat(
    window,
    window.decorView
   ).show(WindowInsetsCompat.Type.systemBars())
}
终陌 2025-02-01 19:55:44

要使应用程序全屏进行全屏,

with(WindowCompat.getInsetsController(window, window.decorView)) {
    systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    hide(WindowInsetsCompat.Type.systemBars())
}

我对Kotlin量身定制的应用程序,因此您需要做的就是将其挂在button's onclick 和你很好。

Button(
  onclick = { /*Paste above Code here*/ }
){
 Text("Go full-screen") // Whatever here, per your use-case
}

如果由于某种原因不起作用,或者无法通过onclick无法访问某些内容,只需使用使用mutableState< boolean>作为钥匙并更改键以触发反应。不需要,很可能是因为OnClick应该正常工作。

To make an app go full-screen, there's

with(WindowCompat.getInsetsController(window, window.decorView)) {
    systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    hide(WindowInsetsCompat.Type.systemBars())
}

Which I've tailored to Kotlin, so all you need to do is just hook it up in a Button's onClick and you're good to go.

Button(
  onclick = { /*Paste above Code here*/ }
){
 Text("Go full-screen") // Whatever here, per your use-case
}

If this does not work for some reason, or something is not accessible through the onClick, just create a LaunchedEffect with a MutableState<Boolean> as the key and change the key to trigger the reaction. Won't be necessary, most probably since the onClick should work just fine.

雨落星ぅ辰 2025-02-01 19:55:44

我有一个示例,该示例实现了完整屏幕,用 compose-media 。您不必使用此库。但是解决方案是相似的。

  1. 为媒体播放实现一个可组合的mediacontent,您可以将全屏切换相对逻辑封装在其中。以下代码将类似于YouTube的全屏切换行为(不是UI)。
@Composable
private fun MediaContent(
    mediaState: MediaState,
    isLandscape: Boolean,
    modifier: Modifier = Modifier
) {
    val activity = LocalContext.current.findActivity()!!
    val enterFullscreen = { activity.requestedOrientation = SCREEN_ORIENTATION_USER_LANDSCAPE }
    val exitFullscreen = {
        @SuppressLint("SourceLockedOrientationActivity")
        // Will reset to SCREEN_ORIENTATION_USER later
        activity.requestedOrientation = SCREEN_ORIENTATION_USER_PORTRAIT
    }
    Box(modifier) {
        Media(
            mediaState,
            modifier = Modifier.fillMaxSize(),
            showBuffering = ShowBuffering.Always,
            buffering = {
                Box(Modifier.fillMaxSize(), Alignment.Center) {
                    CircularProgressIndicator()
                }
            },
        )
        Button(
            modifier = Modifier.align(Alignment.BottomEnd),
            onClick = if (isLandscape) exitFullscreen else enterFullscreen
        ) {
            Text(text = if (isLandscape) "Exit Fullscreen" else "Enter Fullscreen")
        }
    }
    val onBackPressedCallback = remember {
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                exitFullscreen()
            }
        }
    }
    val onBackPressedDispatcher = activity.onBackPressedDispatcher
    DisposableEffect(onBackPressedDispatcher) {
        onBackPressedDispatcher.addCallback(onBackPressedCallback)
        onDispose { onBackPressedCallback.remove() }
    }
    SideEffect {
        onBackPressedCallback.isEnabled = isLandscape
        if (isLandscape) {
            if (activity.requestedOrientation == SCREEN_ORIENTATION_USER) {
                activity.requestedOrientation = SCREEN_ORIENTATION_USER_LANDSCAPE
            }
        } else {
            activity.requestedOrientation = SCREEN_ORIENTATION_USER
        }
    }
}

  1. 然后,您可以使用它:
@Composable
fun FullscreenToggle() {
    val configuration = LocalConfiguration.current
    val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE

    // hide system ui in fullscreen mode, if you need
    val systemUiController = rememberSystemUiController()
    SideEffect {
        systemUiController.isStatusBarVisible = !isLandscape
        systemUiController.isNavigationBarVisible = !isLandscape
    }

    // create and remember a MediaState instance
    val player by rememberManagedExoPlayer()
    val mediaState = rememberMediaState(player)

    // with movableContentOf, MediaContent's node can be reused between toggling
    val mediaContent = remember {
        movableContentOf { isLandscape: Boolean, modifier: Modifier ->
            MediaContent(mediaState, isLandscape, modifier)
        }
    }
    // this is the UI for normal mode, display the MediaContent with other UI elements
    Scaffold(
        topBar = {
          ...
        },
        modifier = Modifier
            .fillMaxSize()
            .systemBarsPadding(),
    ) { padding ->
        if (!isLandscape) {
            mediaContent(
                false,
                Modifier
                    .padding(padding)
                    .fillMaxWidth()
                    .aspectRatio(16f / 9f)
            )
        }
    }
    // this is the UI for fullscreen mode, only display the MediaContent
    if (isLandscape) {
        mediaContent(
            true,
            Modifier
                .fillMaxSize()
                .background(Color.Black)
        )
    }
}

您可以在此处找到完整的代码: https://github.com/fengdai/fengdai/compose-media/blob/blob/master/sample/sample/sramplc/src/main/java/java/java/java/github/github/github/fengdai/compose /Media/sample/fullspreeentoggle.kt

I have an example which implements fullscreen toggling with compose-media. You don't have to use this library. But the solution is similar.

  1. Implement a composable MediaContent for media playback, and you can encapsulate fullscreen toggling relative logic inside it. Below code will work similar to YouTube's fullscreen toggling behavior (not UI).
@Composable
private fun MediaContent(
    mediaState: MediaState,
    isLandscape: Boolean,
    modifier: Modifier = Modifier
) {
    val activity = LocalContext.current.findActivity()!!
    val enterFullscreen = { activity.requestedOrientation = SCREEN_ORIENTATION_USER_LANDSCAPE }
    val exitFullscreen = {
        @SuppressLint("SourceLockedOrientationActivity")
        // Will reset to SCREEN_ORIENTATION_USER later
        activity.requestedOrientation = SCREEN_ORIENTATION_USER_PORTRAIT
    }
    Box(modifier) {
        Media(
            mediaState,
            modifier = Modifier.fillMaxSize(),
            showBuffering = ShowBuffering.Always,
            buffering = {
                Box(Modifier.fillMaxSize(), Alignment.Center) {
                    CircularProgressIndicator()
                }
            },
        )
        Button(
            modifier = Modifier.align(Alignment.BottomEnd),
            onClick = if (isLandscape) exitFullscreen else enterFullscreen
        ) {
            Text(text = if (isLandscape) "Exit Fullscreen" else "Enter Fullscreen")
        }
    }
    val onBackPressedCallback = remember {
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                exitFullscreen()
            }
        }
    }
    val onBackPressedDispatcher = activity.onBackPressedDispatcher
    DisposableEffect(onBackPressedDispatcher) {
        onBackPressedDispatcher.addCallback(onBackPressedCallback)
        onDispose { onBackPressedCallback.remove() }
    }
    SideEffect {
        onBackPressedCallback.isEnabled = isLandscape
        if (isLandscape) {
            if (activity.requestedOrientation == SCREEN_ORIENTATION_USER) {
                activity.requestedOrientation = SCREEN_ORIENTATION_USER_LANDSCAPE
            }
        } else {
            activity.requestedOrientation = SCREEN_ORIENTATION_USER
        }
    }
}

  1. Then you can use it:
@Composable
fun FullscreenToggle() {
    val configuration = LocalConfiguration.current
    val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE

    // hide system ui in fullscreen mode, if you need
    val systemUiController = rememberSystemUiController()
    SideEffect {
        systemUiController.isStatusBarVisible = !isLandscape
        systemUiController.isNavigationBarVisible = !isLandscape
    }

    // create and remember a MediaState instance
    val player by rememberManagedExoPlayer()
    val mediaState = rememberMediaState(player)

    // with movableContentOf, MediaContent's node can be reused between toggling
    val mediaContent = remember {
        movableContentOf { isLandscape: Boolean, modifier: Modifier ->
            MediaContent(mediaState, isLandscape, modifier)
        }
    }
    // this is the UI for normal mode, display the MediaContent with other UI elements
    Scaffold(
        topBar = {
          ...
        },
        modifier = Modifier
            .fillMaxSize()
            .systemBarsPadding(),
    ) { padding ->
        if (!isLandscape) {
            mediaContent(
                false,
                Modifier
                    .padding(padding)
                    .fillMaxWidth()
                    .aspectRatio(16f / 9f)
            )
        }
    }
    // this is the UI for fullscreen mode, only display the MediaContent
    if (isLandscape) {
        mediaContent(
            true,
            Modifier
                .fillMaxSize()
                .background(Color.Black)
        )
    }
}

You can find full code here: https://github.com/fengdai/compose-media/blob/master/sample/src/main/java/com/github/fengdai/compose/media/sample/FullscreenToggle.kt

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文