背景:做一个小窗口实现手机相机预览,可以全屏切换预览画面
实现是采用cameraX api实现摄像头预览,参考了谷歌的实现;CameraXBasic中是一个activity加多个fragment的方式,使用navigation管理页面跳转。
参考CameraXBasic自己的项目也是单activity加fragment,使用navigation管理页面跳转。采用MVVM架构。
问题:预览在一个fragment中在切换到全屏时,当点击返回键,期望变为小窗预览,实际直接退出预览界面了;在网上看了一些文章如https://www.jianshu.com/p/fff1ef649fc0等,感觉都有些麻烦。
项目中使用了ViewModel,就想通过activity和fragment中共用一个ViewModel实例,在ViewModel中保存一个全屏的属性,
val isFullScreen= MutableLiveData()
在activity 中重写onBackPresse()做全屏切换;
override fun onBackPressed() {
if (model.isFullScreen.value ==true) {
model.isFullScreen.value =false
}else {
super.onBackPressed()
}
}
共用一个viewmodel参考官方文档
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
val model:MyViewModel by viewModels()
model.getUsers().observe(this, Observer<List<User>>{ users ->// update UI})}}
class DetailFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate// from the fragment-ktx artifactprivate val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)
model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->// Update the UI})}}
全屏和小窗切换通过在fragment中监听isFullScreen来切换
model.isFullScreen.observe(viewLifecycleOwner, Observer<Boolean> { it ->
if (it) {
mSecondConstraintSet.applyTo(binding.rootContainer)
}else {
mFirstConstraintSet.applyToWithoutCustom(binding.rootContainer)
}
})
其中布局切换使用ConstraintSet 实现,写好全屏和小窗的两个布局即可;
private val mFirstConstraintSet by lazy {
ConstraintSet().apply {
load(requireContext(), R.layout.camera_fragment)
}
}
private val mSecondConstraintSet by lazy {
ConstraintSet().apply {
load(requireContext(), R.layout.camera_fullscreen_fragment)
}
}
还可以添加切换动画
TransitionManager.beginDelayedTransition(binding.rootContainer)
备注:binding.rootContainer是采用了viewBinding,参考
buildFeatures{
// for view binding :
viewBinding =true
}
在没有添加相机预览画面时,全屏切换是从中间切换到全屏,再从全屏切换到正中的小窗
添加视频流后,模拟器上显示效果如下:真机上显示没有小窗后面的视频;
全屏时如下:左上角有一个原来小窗时的隐藏的视频画面
添加动画后,就是从左上角预览画面移动到正中;
不是全屏缩小到正中;摄像头预览使用的androidx.camera.view.PreviewView
具体还没研究什么原因,先把动画去掉了