使用exo播放器添加全屏视频按钮

时间:2016-05-02 19:29:10

标签: android exoplayer

我正在使用exoPlayer将视频流式传输到我的应用程序,到目前为止工作正常。我现在想做的是添加一些额外的功能,例如右下角的按钮,作为“全屏按钮”。

但有两个问题。首先,ExoPlayer似乎没有提供任何Control类,因此您可以简单地添加按钮并覆盖其功能。 我想我必须在视频顶部显示该按钮,这样我可能必须将它们包裹在FrameLayout中并为按钮添加gravity = bottom或者是否有另一种方式?

第二个问题是:如果用户点击全屏按钮,我接下来该怎么办?全视频添加另一个Fragment视频视图?但是,如何从用户点击按钮开始播放视频,而不是从头开始播放?我无法在exoPlayer中找到与特定时间相关的任何内容。

3 个答案:

答案 0 :(得分:8)

如果您使用的是SimpleExoPlayerView,则可以自定义播放器的视图,尤其是Control的视图。查看SimpleExoPlayerView的文档:

  

<强>属性

     

在布局XML文件中使用时,可以在SimpleExoPlayerView上设置以下属性:   ...

     

controller_layout_id - 指定要由子PlaybackControlView充气的布局资源的ID。有关详细信息,请参见下文。

     
      
  • 对应方法:无

  •   
  • 默认值: R.id.exo_playback_control_view

  •   
     

...

基本上,您可以为控制器提供自己的布局文件(您可以复制文档中提到的 exo_playback_control_view 布局,这是默认布局,并根据需要自定义。注意您需要为现有控件提供相同的视图ID(因此最好实际复制它),如PlaybackControlView的文档中所述:

  

覆盖布局文件

     

要在整个应用程序中自定义PlaybackControlView的布局,或仅针对某些配置,您可以在应用程序res / layout *目录中定义 exo_playback_control_view.xml 布局文件。这些布局将覆盖 ExoPlayer 库提供的布局,并且会被PlaybackControlView使用。该视图通过查找以下ID来标识并绑定其子项:

     
      
  • exo_play - 播放按钮。

  •   
  • exo_pause - 暂停按钮。

  •   
  • exo_ffwd - 快进按钮。

  •   
  • exo_rew - 倒带按钮。

  •   
  • exo_prev - 上一曲目按钮。

  •   
  • exo_next - 下一个曲目按钮。

  •   
  • exo_position - 显示当前播放位置的文字视图。

  •   
  • exo_duration - 显示当前媒体持续时间的文字视图。

  •   
  • exo_progress - 寻找在播放期间更新的栏,并允许搜索。

  •   
     

所有子视图都是可选的,因此如果不需要,可以省略,但是如果定义它们必须是预期的类型。

以下是带全屏按钮的自定义布局。您可以view.findViewById(R.id.exo_fullscreen_button)获得对该按钮的引用,并将OnClickListener附加到该按钮。在onClick()内,您可以开始全屏活动(您可以在 AndroidManifest.xml 中或以编程方式定义它的全屏)或显示另一个片段,其中SimpleExoPlayerView占用整个屏幕。 从第二点开始,您可以获得如下的播放位置:playbackPosition = player.getCurrentPosition()并将其作为Intent extra传递给新的全屏Activity / Fragment。然后,在全屏活动/片段中加载视频,提取playbackPosition值并调用:

player.seekTo(playbackPosition);
player.setPlayWhenReady(true);

这是控件布局文件:          

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingTop="4dp"
    android:orientation="horizontal">

    <ImageButton android:id="@id/exo_prev"
      style="@style/ExoMediaButton.Previous"/>

    <ImageButton android:id="@id/exo_rew"
      style="@style/ExoMediaButton.Rewind"/>

    <ImageButton android:id="@id/exo_play"
      style="@style/ExoMediaButton.Play"/>

    <ImageButton android:id="@id/exo_pause"
      style="@style/ExoMediaButton.Pause"/>

    <ImageButton android:id="@id/exo_ffwd"
      style="@style/ExoMediaButton.FastForward"/>

    <ImageButton android:id="@id/exo_next"
      style="@style/ExoMediaButton.Next"/>

    // This is the custom button
    <ImageButton
        android:id="@+id/exo_fullscreen_button"
        style="@style/ExoMediaButton"
        android:src="@drawable/ic_fullscreen"/>
  </LinearLayout>

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="4dp"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <TextView android:id="@id/exo_position"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textSize="14sp"
      android:textStyle="bold"
      android:paddingLeft="4dp"
      android:paddingRight="4dp"
      android:includeFontPadding="false"
      android:textColor="#FFBEBEBE"/>

    <SeekBar android:id="@id/exo_progress"
      android:layout_width="0dp"
      android:layout_weight="1"
      android:layout_height="32dp"
      android:focusable="false"
      style="?android:attr/progressBarStyleHorizontal"/>

    <TextView android:id="@id/exo_duration"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textSize="14sp"
      android:textStyle="bold"
      android:paddingLeft="4dp"
      android:paddingRight="4dp"
      android:includeFontPadding="false"
      android:textColor="#FFBEBEBE"/>

  </LinearLayout>

</LinearLayout>

答案 1 :(得分:1)

在当前活动上方具有新的全屏活动的解决方案,将播放位置传递给该活动

other answer很不错,可以为您指出正确的方向,但这是理论上的问题,在编写代码时,我仍然需要填补一些空白并解决一些问题。我会尽力补充它。

首先将布局exo_playback_control_view.xml从ExoPlayer库复制到res/layout。档案连结:https://github.com/google/ExoPlayer/blob/release-v2/library/ui/src/main/res/layout/exo_playback_control_view.xml

修改布局以添加全屏按钮,可以是这样:

<FrameLayout
    android:id="@+id/exo_fullscreen_button"
    android:layout_width="32dp"
    android:layout_height="32dp"
    android:layout_gravity="end">

    <ImageView
        android:layout_width="18dp"
        android:layout_height="18dp"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@drawable/ic_fullscreen_expand"
        android:focusable="true" />

</FrameLayout>

请注意,通过使用属性PlayerView,可以为不同的app:controller_layout_id使用不同的布局。如果您不想播放器按钮,也可以删除它们。在文档中对此进行了介绍:https://exoplayer.dev/ui-components.html#overriding-layout-files

具有全屏按钮后,在其上设置一个OnClickListener

findViewById<View>(R.id.exo_fullscreen_button).setOnClickListener {
    player.playWhenReady = false // pause current video if it's playing
    startActivity(
        FullScreenVideoActivity.newIntent(
            context,
            videoUrl,
            player.currentPosition
        )
    )
}

添加FullScreenVideoActivity

private const val EXTRA_VIDEO_URL = "EXTRA_VIDEO_URL"
private const val EXTRA_PLAYBACK_POSITION_MS = "EXTRA_PLAYBACK_POSITION_MS"

private const val STATE_PLAYBACK_POSITION_MS = "STATE_PLAYBACK_POSITION_MS"

class FullScreenVideoActivity : AppCompatActivity() {

    companion object {
        fun newIntent(packageContext: Context, videoUrl: String, playbackPositionMs: Long): Intent {
            val intent =
                Intent(packageContext, FullScreenVideoActivity::class.java)
            intent.putExtra(EXTRA_VIDEO_URL, videoUrl)
            intent.putExtra(EXTRA_PLAYBACK_POSITION_MS, playbackPositionMs)
            return intent
        }
    }

    private lateinit var player: SimpleExoPlayer

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_full_screen_video)

        val videoUrl = intent.getStringExtra(EXTRA_VIDEO_URL)
        var playbackPositionMs = intent.getLongExtra(EXTRA_PLAYBACK_POSITION_MS, 0)

        if (savedInstanceState != null) {
            // The user rotated the screen
            playbackPositionMs = savedInstanceState.getLong(STATE_PLAYBACK_POSITION_MS)
        }

        findViewById<View>(R.id.exo_fullscreen_button).setOnClickListener {
            finish()
        }

        val playerView: PlayerView = findViewById(R.id.player_view)
        player = ExoPlayerFactory.newSimpleInstance(this)
        val userAgent = Util.getUserAgent(this, getString(R.string.app_name))
        val dataSourceFactory = DefaultDataSourceFactory(this, userAgent)
        val mediaSource: MediaSource =
            ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(videoUrl))
        player.prepare(mediaSource)
        player.seekTo(playbackPositionMs)
        player.playWhenReady = true
        playerView.player = player
    }

    override fun onPause() {
        super.onPause()
        player.playWhenReady = false
    }

    override fun onDestroy() {
        super.onDestroy()
        player.release()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putLong(STATE_PLAYBACK_POSITION_MS, player.currentPosition)
    }

}

将活动添加到清单:

<activity
    android:name=".ui.FullScreenVideoActivity"
    android:screenOrientation="landscape" <-- this is optional
    android:theme="@style/AppTheme.NoActionBar.FullScreen" />

最后将主题添加到styles.xml

<style name="AppTheme.NoActionBar.FullScreen">
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>
</style>

仅此而已!希望对您有所帮助。

当前活动中的替代解决方案

上述解决方案可以正常工作,而且很简单。但是,它需要重新下载您已经下载的视频的某些位,这会中断播放:/

我一直在尝试通过遵循this directions来避免这种情况。这是我到目前为止的内容:

activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
val fullScreenPlayerView = PlayerView(context)
val dialog = object : Dialog(context!!, android.R.style.Theme_Black_NoTitleBar_Fullscreen) {
    override fun onBackPressed() {
        activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        PlayerView.switchTargetView(player, fullScreenPlayerView, playerView)
        super.onBackPressed()
    }
}
dialog.addContentView(
    fullScreenPlayerView,
    ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT
    )
)
dialog.show()
PlayerView.switchTargetView(player, playerView, fullScreenPlayerView)

请注意,要执行此操作,您必须在清单中的“活动”中设置android:configChanges="orientation|screenSize|layoutDirection"

答案 2 :(得分:0)

我为此做了一个kotlin扩展功能。 您需要两个Exoplayer,并且扩展程序将在两个播放器(全屏和常规)之间切换。

    <data
                android:scheme="https"
                android:host="www.example.com"
                android:pathPrefix="/landingPage" />
</intent-filter>

例如具有这种布局:

    @SuppressLint("SourceLockedOrientationActivity")
fun SimpleExoPlayer.preparePlayer(playerView: PlayerView, playerViewFullscreen: PlayerView) {

    (playerView.context as AppCompatActivity).apply {
        val fullScreenButton: ImageView = playerView.findViewById(R.id.exo_fullscreen_icon)
        val normalScreenButton: ImageView = playerViewFullscreen.findViewById(R.id.exo_fullscreen_icon)
        fullScreenButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_fullscreen_open))
        normalScreenButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_fullscreen_close))

        fullScreenButton.setOnClickListener {
            window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
            supportActionBar?.hide()
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
            playerView.visibility = View.GONE
            playerViewFullscreen.visibility = View.VISIBLE
            PlayerView.switchTargetView(this@preparePlayer, playerView, playerViewFullscreen)
        }

        normalScreenButton.setOnClickListener {
            window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
            supportActionBar?.show()
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
            normalScreenButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_fullscreen_close))
            playerView.visibility = View.VISIBLE
            playerViewFullscreen.visibility = View.GONE
            PlayerView.switchTargetView(this@preparePlayer, playerViewFullscreen, playerView)
        }

        playerView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT
        playerView.player = this@preparePlayer
    }

}

fun SimpleExoPlayer.setSource(context: Context, url: String){
    val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(context, Util.getUserAgent(context, "app"))
    val videoSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(url))
    this.prepare(videoSource)
}

您可以像这样使用它:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true"
    tools:context=".MainActivity">

     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="300dp">

          <com.google.android.exoplayer2.ui.PlayerView
              android:id="@+id/playerView"
              android:layout_width="match_parent"
              android:layout_height="match_parent" />

     </RelativeLayout>

     <com.google.android.exoplayer2.ui.PlayerView
         android:id="@+id/playerViewFullscreen"
         android:visibility="gone"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />

</RelativeLayout>

如果您不想复制此代码,则可以添加此库。效果相同:https://github.com/Norulab/android-exoplayer-fullscreen