我正在使用exoPlayer将视频流式传输到我的应用程序,到目前为止工作正常。我现在想做的是添加一些额外的功能,例如右下角的按钮,作为“全屏按钮”。
但有两个问题。首先,ExoPlayer
似乎没有提供任何Control类,因此您可以简单地添加按钮并覆盖其功能。
我想我必须在视频顶部显示该按钮,这样我可能必须将它们包裹在FrameLayout
中并为按钮添加gravity = bottom或者是否有另一种方式?
第二个问题是:如果用户点击全屏按钮,我接下来该怎么办?全视频添加另一个Fragment
视频视图?但是,如何从用户点击按钮开始播放视频,而不是从头开始播放?我无法在exoPlayer中找到与特定时间相关的任何内容。
答案 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