视频组件优化

This commit is contained in:
2026-05-28 16:08:54 +08:00
parent bb0d3278d9
commit b2d3046560
7 changed files with 147 additions and 120 deletions

View File

@@ -29,6 +29,7 @@ import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.bean.FamilyBean import com.example.defenseapplication.bean.FamilyBean
import com.example.defenseapplication.bean.SwitchFamilyRequest import com.example.defenseapplication.bean.SwitchFamilyRequest
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
import com.example.defenseapplication.liveVideo.LiveVideoActivity
import com.example.defenseapplication.utils.DeviceIdEvent import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUpdateEvent import com.example.defenseapplication.utils.DeviceUpdateEvent
import com.example.defenseapplication.utils.FamilySwitchEvent import com.example.defenseapplication.utils.FamilySwitchEvent
@@ -461,7 +462,7 @@ class HomeMenuFragment : Fragment() {
private fun onDeviceClicked(device: DeviceUi) { private fun onDeviceClicked(device: DeviceUi) {
if (device.isOnline) { if (device.isOnline) {
DeviceIdEvent.setDeviceId(device.deviceId) DeviceIdEvent.setDeviceId(device.deviceId)
val intent = Intent(requireContext(), com.example.defenseapplication.liveVideo.LiveVideoActivity::class.java) val intent = Intent(requireContext(), LiveVideoActivity::class.java)
intent.putExtra("device_name", device.name) intent.putExtra("device_name", device.name)
startActivity(intent) startActivity(intent)
} else { } else {

View File

@@ -1,10 +1,13 @@
package com.example.defenseapplication.liveVideo package com.example.defenseapplication.liveVideo
import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.Toast import android.widget.Toast
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
@@ -13,9 +16,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
import chuangyuan.ycj.videolibrary.listener.VideoInfoListener import chuangyuan.ycj.videolibrary.listener.VideoInfoListener
import chuangyuan.ycj.videolibrary.video.ExoUserPlayer import chuangyuan.ycj.videolibrary.video.ExoUserPlayer
import chuangyuan.ycj.videolibrary.video.VideoPlayerManager import chuangyuan.ycj.videolibrary.video.VideoPlayerManager
import com.google.android.exoplayer2.ui.PlayerView
import com.example.defenseapplication.R import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.AlarmLogAdapter import com.example.defenseapplication.adapter.AlarmLogAdapter
import com.example.defenseapplication.databinding.AlarmLogActivityBinding import com.example.defenseapplication.databinding.AlarmLogActivityBinding
import com.example.defenseapplication.utils.ActivityManager
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import java.util.* import java.util.*
import com.bigkoo.pickerview.builder.TimePickerBuilder import com.bigkoo.pickerview.builder.TimePickerBuilder
@@ -28,6 +33,9 @@ class AlarmLogActivity : AppCompatActivity() {
private var adapter: AlarmLogAdapter? = null private var adapter: AlarmLogAdapter? = null
private val alarmList = mutableListOf<String>() private val alarmList = mutableListOf<String>()
private lateinit var exoPlayerManager: ExoUserPlayer private lateinit var exoPlayerManager: ExoUserPlayer
private var isMuted = false
private var isVoiceEnabled = false
private var isLightOn = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -94,6 +102,39 @@ class AlarmLogActivity : AppCompatActivity() {
.create() .create()
exoPlayerManager.startPlayer() exoPlayerManager.startPlayer()
setupControllerVisibilityListener()
}
private fun setupControllerVisibilityListener() {
binding.exoPlayContextId.post {
val playerView = findPlayerView(binding.exoPlayContextId)
playerView?.setControllerVisibilityListener { visibility ->
if (visibility == View.VISIBLE) {
binding.muteBar.visibility = View.VISIBLE
binding.functionBar.visibility = View.VISIBLE
} else {
binding.muteBar.visibility = View.GONE
binding.functionBar.visibility = View.GONE
}
}
}
}
private fun findPlayerView(view: View): PlayerView? {
if (view is PlayerView) {
return view
}
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val child = view.getChildAt(i)
val found = findPlayerView(child)
if (found != null) {
return found
}
}
}
return null
} }
private fun initRecyclerView() { private fun initRecyclerView() {
@@ -122,6 +163,37 @@ class AlarmLogActivity : AppCompatActivity() {
binding.expandImg.setOnClickListener { binding.expandImg.setOnClickListener {
showDatePicker() showDatePicker()
} }
binding.ivMute.setOnClickListener {
toggleMute()
}
binding.ivDownload.setOnClickListener {
downloadVideo()
}
binding.ivDelete.setOnClickListener {
deleteVideo()
}
}
private fun toggleMute() {
isMuted = !isMuted
if (isMuted) {
binding.ivMute.setImageResource(R.drawable.mute)
Toast.makeText(this, R.string.sound_off, Toast.LENGTH_SHORT).show()
} else {
binding.ivMute.setImageResource(R.drawable.voice)
Toast.makeText(this, R.string.sound_on, Toast.LENGTH_SHORT).show()
}
}
private fun downloadVideo() {
Toast.makeText(this, R.string.download, Toast.LENGTH_SHORT).show()
}
private fun deleteVideo() {
Toast.makeText(this, R.string.delete, Toast.LENGTH_SHORT).show()
} }
override fun onResume() { override fun onResume() {
@@ -158,7 +230,7 @@ class AlarmLogActivity : AppCompatActivity() {
val params = binding.exoPlayContextId.layoutParams val params = binding.exoPlayContextId.layoutParams
params.width = LinearLayout.LayoutParams.MATCH_PARENT params.width = LinearLayout.LayoutParams.MATCH_PARENT
params.height = dpToPx(250) params.height = dpToPx(280)
binding.exoPlayContextId.layoutParams = params binding.exoPlayContextId.layoutParams = params
} }

View File

@@ -23,11 +23,7 @@ import androidx.activity.OnBackPressedCallback
import chuangyuan.ycj.videolibrary.listener.VideoInfoListener import chuangyuan.ycj.videolibrary.listener.VideoInfoListener
import chuangyuan.ycj.videolibrary.video.VideoPlayerManager import chuangyuan.ycj.videolibrary.video.VideoPlayerManager
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
//智能防御机A1
class LiveVideoActivity : BaseActivity() { class LiveVideoActivity : BaseActivity() {
private lateinit var binding: LiveVideoActivityBinding private lateinit var binding: LiveVideoActivityBinding
@@ -37,8 +33,6 @@ class LiveVideoActivity : BaseActivity() {
private var isRecording = false private var isRecording = false
private var mediaRecorder: MediaRecorder? = null private var mediaRecorder: MediaRecorder? = null
private var micPulseAnimation: ScaleAnimation? = null private var micPulseAnimation: ScaleAnimation? = null
private var isFullscreen = false
private var fullscreenBackButton: ImageView? = null
private val requestPermissionLauncher = registerForActivityResult( private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission() ActivityResultContracts.RequestPermission()
@@ -56,7 +50,6 @@ class LiveVideoActivity : BaseActivity() {
binding = LiveVideoActivityBinding.inflate(layoutInflater) binding = LiveVideoActivityBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
// ImmersionBar核心调用,沉浸式
ImmersionBar.with(this) ImmersionBar.with(this)
.statusBarDarkFont(true) .statusBarDarkFont(true)
.titleBar(binding.topBar) .titleBar(binding.topBar)
@@ -67,7 +60,6 @@ class LiveVideoActivity : BaseActivity() {
binding.tvTitle.text = deviceName binding.tvTitle.text = deviceName
} }
// 初始化播放器
initVideoPlayer() initVideoPlayer()
initListener() initListener()
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
@@ -75,25 +67,23 @@ class LiveVideoActivity : BaseActivity() {
if (exoPlayerManager.onBackPressed()) { if (exoPlayerManager.onBackPressed()) {
return return
} }
// 无全屏时执行默认返回逻辑(如 finish
finish() finish()
} }
}) })
} }
private fun initVideoPlayer() { private fun initVideoPlayer() {
val videoPlayerView = binding.exoPlayContextId val videoPlayerView = binding.exoPlayContextId
exoPlayerManager = VideoPlayerManager.Builder(VideoPlayerManager.TYPE_PLAY_GESTURE, videoPlayerView) exoPlayerManager = VideoPlayerManager.Builder(VideoPlayerManager.TYPE_PLAY_GESTURE, videoPlayerView)
.setPlayUri("https://media.w3.org/2010/05/sintel/trailer.mp4")//真实地址 .setPlayUri("https://media.w3.org/2010/05/sintel/trailer.mp4")
.setPosition(0) .setPosition(0)
.addVideoInfoListener(object : VideoInfoListener { .addVideoInfoListener(object : VideoInfoListener {
// 注意:此处的 p0: Long 是视频开始播放时的位置信息,可以按需使用
override fun onPlayStart(p0: Long) { override fun onPlayStart(p0: Long) {
Log.d("AlarmLogActivity", "视频开始播放") Log.d("LiveVideoActivity", "视频开始播放")
} }
override fun onLoadingChanged() { override fun onLoadingChanged() {
// 视频加载状态变化
} }
override fun onPlayerError(p0: com.google.android.exoplayer2.ExoPlaybackException?) { override fun onPlayerError(p0: com.google.android.exoplayer2.ExoPlaybackException?) {
@@ -101,93 +91,18 @@ class LiveVideoActivity : BaseActivity() {
} }
override fun onPlayEnd() { override fun onPlayEnd() {
Log.d("AlarmLogActivity", "播放结束") Log.d("LiveVideoActivity", "播放结束")
} }
// 修正点:库的接口要求必须实现 isPlaying 方法
override fun isPlaying(p0: Boolean) { override fun isPlaying(p0: Boolean) {
// p0 表示当前是否正在播放
} }
fun onRepeatModeChanged(p0: Int) { fun onRepeatModeChanged(p0: Int) {
// 循环模式改变时的回调
} }
}) })
.create() .create()
exoPlayerManager.startPlayer() exoPlayerManager.startPlayer()
setupFullscreenListener()
}
private fun setupFullscreenListener() {
binding.exoPlayContextId.setOnClickListener {
if (!isFullscreen) {
enterFullscreen()
}
}
}
private fun enterFullscreen() {
isFullscreen = true
binding.topBar.visibility = View.GONE
binding.functionBar.visibility = View.GONE
val params = binding.exoPlayContextId.layoutParams
params.width = LinearLayout.LayoutParams.MATCH_PARENT
params.height = LinearLayout.LayoutParams.MATCH_PARENT
binding.exoPlayContextId.layoutParams = params
exoPlayerManager.onConfigurationChanged(Configuration().apply {
orientation = Configuration.ORIENTATION_LANDSCAPE
})
showFullscreenBackButton()
}
private fun exitFullscreen() {
isFullscreen = false
binding.topBar.visibility = View.VISIBLE
binding.functionBar.visibility = View.VISIBLE
val params = binding.exoPlayContextId.layoutParams
params.width = LinearLayout.LayoutParams.MATCH_PARENT
params.height = 250
binding.exoPlayContextId.layoutParams = params
exoPlayerManager.onConfigurationChanged(Configuration().apply {
orientation = Configuration.ORIENTATION_PORTRAIT
})
hideFullscreenBackButton()
}
private fun showFullscreenBackButton() {
fullscreenBackButton = ImageView(this).apply {
setImageResource(R.drawable.back_white)
scaleType = ImageView.ScaleType.CENTER_CROP
val params = LinearLayout.LayoutParams(60, 60)
params.topMargin = 60
params.leftMargin = 20
layoutParams = params
setOnClickListener {
exitFullscreen()
}
}
(binding.root as ViewGroup).addView(fullscreenBackButton)
fullscreenBackButton?.bringToFront()
}
private fun hideFullscreenBackButton() {
fullscreenBackButton?.let {
(binding.root as ViewGroup).removeView(it)
fullscreenBackButton = null
}
} }
private fun initListener() { private fun initListener() {
@@ -203,6 +118,7 @@ class LiveVideoActivity : BaseActivity() {
val intent = Intent(this, SettingsActivity::class.java) val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent) startActivity(intent)
} }
binding.llVoice.setOnClickListener { binding.llVoice.setOnClickListener {
toggleVoice() toggleVoice()
} }
@@ -219,14 +135,12 @@ class LiveVideoActivity : BaseActivity() {
Toast.makeText(this, R.string.view_alarm_log, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.view_alarm_log, Toast.LENGTH_SHORT).show()
} }
// 点击xq箭头跳转到AlarmLogActivity
binding.xq.setOnClickListener { binding.xq.setOnClickListener {
val intent = Intent(this, AlarmLogActivity::class.java) val intent = Intent(this, AlarmLogActivity::class.java)
startActivity(intent) startActivity(intent)
} }
} }
private fun toggleVoice() { private fun toggleVoice() {
isVoiceEnabled = !isVoiceEnabled isVoiceEnabled = !isVoiceEnabled
@@ -278,20 +192,14 @@ class LiveVideoActivity : BaseActivity() {
isRecording = true isRecording = true
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy_open) binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy_open)
// 隐藏告警日志区域,显示控制台区域
binding.llAlarmLog.visibility = View.GONE binding.llAlarmLog.visibility = View.GONE
binding.consoleBar.visibility = View.VISIBLE binding.consoleBar.visibility = View.VISIBLE
// 麦克风切换成开启状态
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice_on_open) binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice_on_open)
isVoiceEnabled = true isVoiceEnabled = true
// 启动语音录制
startVoiceRecording() startVoiceRecording()
// 启动麦克风脉冲动画
//startMicPulseAnimation()
Toast.makeText(this, R.string.start_control_mode, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.start_control_mode, Toast.LENGTH_SHORT).show()
} }
@@ -299,24 +207,18 @@ class LiveVideoActivity : BaseActivity() {
isRecording = false isRecording = false
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy) binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy)
// 显示告警日志区域,隐藏控制台区域
binding.llAlarmLog.visibility = View.VISIBLE binding.llAlarmLog.visibility = View.VISIBLE
binding.consoleBar.visibility = View.GONE binding.consoleBar.visibility = View.GONE
// 麦克风切换成关闭状态
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice) binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice)
isVoiceEnabled = false isVoiceEnabled = false
// 停止语音录制
stopVoiceRecording() stopVoiceRecording()
// 停止麦克风脉冲动画
stopMicPulseAnimation() stopMicPulseAnimation()
Toast.makeText(this, R.string.stop_control_mode, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.stop_control_mode, Toast.LENGTH_SHORT).show()
} }
private fun stopMicPulseAnimation() { private fun stopMicPulseAnimation() {
micPulseAnimation?.let { micPulseAnimation?.let {
binding.ivVoice.clearAnimation() binding.ivVoice.clearAnimation()
@@ -358,6 +260,7 @@ class LiveVideoActivity : BaseActivity() {
mediaRecorder = null mediaRecorder = null
} }
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
exoPlayerManager.onResume() exoPlayerManager.onResume()
@@ -375,9 +278,6 @@ class LiveVideoActivity : BaseActivity() {
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
// 横竖屏切换时通知播放器
exoPlayerManager.onConfigurationChanged(newConfig) exoPlayerManager.onConfigurationChanged(newConfig)
} }
} }

View File

@@ -7,13 +7,66 @@
android:background="#F9F9F9" android:background="#F9F9F9"
android:orientation="vertical"> android:orientation="vertical">
<!-- 视频播放区域和悬浮按钮 -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 视频播放区域 --> <!-- 视频播放区域 -->
<chuangyuan.ycj.videolibrary.widget.VideoPlayerView <chuangyuan.ycj.videolibrary.widget.VideoPlayerView
android:id="@+id/exoPlayContextId" android:id="@+id/exoPlayContextId"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="250dp" android:layout_height="280dp"
android:background="@android:color/transparent" android:background="@android:color/transparent"
app:use_controller="true" /> app:use_controller="true" />
<!-- 右上角按钮区域 - 下载和删除横向排列 -->
<LinearLayout
android:id="@+id/functionBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginTop="40dp"
android:layout_marginEnd="6dp"
android:orientation="horizontal"
android:visibility="gone">
<ImageView
android:id="@+id/ivDownload"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="8dp"
android:src="@drawable/download"/>
<ImageView
android:id="@+id/ivDelete"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="12dp"
android:padding="8dp"
android:src="@drawable/delete"/>
</LinearLayout>
<!-- 右下角按钮区域 - 静音按钮 -->
<LinearLayout
android:layout_marginBottom="40dp"
android:id="@+id/muteBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="6dp"
android:visibility="gone">
<ImageView
android:id="@+id/ivMute"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="8dp"
android:src="@drawable/mute"/>
</LinearLayout>
</FrameLayout>
<LinearLayout <LinearLayout

View File

@@ -6,7 +6,6 @@
android:background="#F5F6F6" android:background="#F5F6F6"
android:name=".liveVideo.LiveVideoActivity" android:name=".liveVideo.LiveVideoActivity"
android:configChanges="orientation|screenSize|keyboardHidden" android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
android:orientation="vertical"> android:orientation="vertical">
<!-- 顶部导航栏 --> <!-- 顶部导航栏 -->
@@ -50,7 +49,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="250dp" android:layout_height="250dp"
android:background="@android:color/transparent" android:background="@android:color/transparent"
app:use_controller="false"/> app:use_controller="true"/>
<!-- 功能按钮区域 --> <!-- 功能按钮区域 -->
<LinearLayout <LinearLayout

View File

@@ -347,6 +347,7 @@
<string name="exited_fullscreen">已退出全屏</string> <string name="exited_fullscreen">已退出全屏</string>
<string name="sound_on">声音已开启</string> <string name="sound_on">声音已开启</string>
<string name="sound_off">声音已关闭</string> <string name="sound_off">声音已关闭</string>
<string name="download">下载</string>
<string name="light_on">灯光已开启</string> <string name="light_on">灯光已开启</string>
<string name="light_off">灯光已关闭</string> <string name="light_off">灯光已关闭</string>
<string name="start_control_mode">开始控制模式</string> <string name="start_control_mode">开始控制模式</string>

View File

@@ -338,6 +338,7 @@
<string name="exited_fullscreen">Exited fullscreen</string> <string name="exited_fullscreen">Exited fullscreen</string>
<string name="sound_on">Sound on</string> <string name="sound_on">Sound on</string>
<string name="sound_off">Sound off</string> <string name="sound_off">Sound off</string>
<string name="download">Download</string>
<string name="light_on">Light on</string> <string name="light_on">Light on</string>
<string name="light_off">Light off</string> <string name="light_off">Light off</string>
<string name="start_control_mode">Start control mode</string> <string name="start_control_mode">Start control mode</string>