在 BottomsheetDialogFragment 中加载包含 exoplayer 磁贴的现有片段时,Exoplayer 视频在滚动时会超出 BottomsheetDialogFragment 的范围。
尝试了很多改变样式、行为、嵌套滚动视图等的解决方案,但没有解决问题。
ReelBottomSheetDialogFragment.class
import android.app.Dialog
import android.content.DialogInterface
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.WindowManager
import androidx.databinding.DataBindingUtil
import com.caratlane.android.Fragments.ListingPageFragment
import com.caratlane.android.R
import com.caratlane.android.Utils.Constants
import com.caratlane.android.Utils.Constants.ReelsKey.PDP_ORIGIN_KEY
import com.caratlane.android.Utils.Constants.ReelsKey.PRODUCT_SKU
import com.caratlane.android.Utils.Methods
import com.caratlane.android.activity.CLBaseToolbarActivity
import com.caratlane.android.activity.MainActivity
import com.caratlane.android.activity.ShoppingCartActivity
import com.caratlane.android.databinding.LayoutProductDetailBottomSheetBinding
import com.caratlane.android.mvvm.home.view.HomeFragment
import com.caratlane.android.mvvm.listing.view.ListingFragment
import com.caratlane.android.mvvm.loginFeature.model.apimodel.NavigationSource
import com.caratlane.android.mvvm.loginFeature.view.fragments.LoginLandingFragment
import com.caratlane.android.mvvm.reels.view.ReelsFragment
import com.caratlane.android.mvvm.reviewsratings.view.BaseProductDetailFragment
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
class ReelBottomSheetDialogFragment : BottomSheetDialogFragment(),
LoginLandingFragment.LogInCallback{
var binding: LayoutProductDetailBottomSheetBinding? = null
var onReelsBottomSheetStatusChange: OnBottomSheetStatusChange? = null
var onPdpBottomSheetStatusChange: OnBottomSheetStatusChange? = null
private var logInReelListener: LoginLandingFragment.LogInCallback? = null
var sku: String? = null
var reelClickedListner : ReelClickedListener? =null
override fun getTheme(): Int {
return R.style.AppBottomSheetDialogTheme
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
(activity as CLBaseToolbarActivity?)?.hideToolBar()
(activity as CLBaseToolbarActivity?)?.hideBackToolbar()
return if (arguments?.getBoolean(ReelsFragment.OPEN_PDP, false) == true) {
sku = arguments?.getString(PRODUCT_SKU)
addProductDetailFragment()
//BottomSheetDialog(requireContext(), theme)
openFullExpandedBottomSheet()
} else {
openLoginFragment()
openFullExpandedBottomSheet()
}
}
private fun openFullExpandedBottomSheet(): BottomSheetDialog {
val dialog = BottomSheetDialog(requireContext(), theme)
dialog.setOnShowListener {
val bottomSheetDialog = it as BottomSheetDialog
val parentLayout =
bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
parentLayout?.let { it ->
val behaviour = BottomSheetBehavior.from(it)
//setupFullHeight(it)
behaviour.state = BottomSheetBehavior.STATE_COLLAPSED
behaviour.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
/* if (newState == BottomSheetBehavior.STATE_EXPANDED) {
// Bottom sheet is expanded, change status bar color
//changeStatusBarColor(getResources().getColor(R.color.black))
setStatusBarColor(getResources().getColor(R.color.black))
} else {
// Revert to default status bar color when bottom sheet is closed
//changeStatusBarColor(resources.getColor(R.color.white))
setStatusBarColor(getResources().getColor(R.color.black))
}*/
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
//updateStatusBarColor(R.color.black)
//changeStatusBarColor(R.color.black)
}
})
}
}
return dialog
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(
LayoutInflater.from(context),
R.layout.layout_product_detail_bottom_sheet,
container,
false
)
return binding?.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
view.viewTreeObserver.removeOnGlobalLayoutListener(this)
dialog?.setOnShowListener {
}
}
})
}
private fun setupFullHeight(bottomSheet: View) {
val layoutParams = bottomSheet.layoutParams
layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT
bottomSheet.layoutParams = layoutParams
}
private fun addProductDetailFragment() {
val productDetailFragment = BaseProductDetailFragment()
arguments?.putBoolean("isToolbarVisible", false)
arguments?.putString(PDP_ORIGIN_KEY, arguments?.getString(PDP_ORIGIN_KEY))
arguments?.putString(
Constants.ReelsKey.IS_FROM,
Constants.ReelsKey.REELS_PAGE
)
productDetailFragment.arguments = arguments
productDetailFragment.takeCallback(object : BaseProductDetailFragment.ViewClick{
override fun onAnyViewClicked() {
Log.d("bottomsheetdialogfragment","in on click")
dialog?.dismiss()
}
override fun onReelClicked(videoId: Long) {
Log.d("bottomsheetdialogfragment","reel video id "+videoId.toString())
reelClickedListner?.onReelClickedFromPdTray(videoId)
}
})
val fragmentManager = childFragmentManager.beginTransaction()
fragmentManager.replace(R.id.product_detail_container, productDetailFragment, productDetailFragment.tag)
fragmentManager.commit()
}
override fun onResume() {
super.onResume()
if (sku != null) {
onPdpBottomSheetStatusChange?.onPDBottomSheetOpened(sku)
onReelsBottomSheetStatusChange?.onPDBottomSheetOpened(sku)
}
}
fun setPdpBottomSheetOpenListener(listener: OnBottomSheetStatusChange) {
onPdpBottomSheetStatusChange = listener
}
fun setReelsBottomSheetStatusChangeListener(listener: OnBottomSheetStatusChange){
onReelsBottomSheetStatusChange = listener
}
private fun openLoginFragment() {
if (!Methods.isActivityAlive(activity)) return
val loginLandingFragment: LoginLandingFragment = if (activity is MainActivity) {
(activity as MainActivity).signInSignUpFragment
} else {
(activity as ShoppingCartActivity).signInSignUpFragment
}
val arguments = Bundle()
arguments.putSerializable(
Constants.BUNDLE_EXTRAS.SOURCE_NAV,
NavigationSource.ReelsPage
)
loginLandingFragment.arguments = arguments
loginLandingFragment.setLoginListener(this)
childFragmentManager.beginTransaction()
.add(R.id.product_detail_container, loginLandingFragment, loginLandingFragment.tag)
.commitAllowingStateLoss()
}
fun setLoginListener(listener : LoginLandingFragment.LogInCallback){
logInReelListener = listener
}
override fun onLoginSuccess() {
logInReelListener?.onLoginSuccess()
dismiss()
}
override fun onLoginBackPressed() {
dialog?.dismiss()
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
if (sku != null) {
onPdpBottomSheetStatusChange?.onPDBottomSheetClose(sku)
onReelsBottomSheetStatusChange?.onPDBottomSheetClose(sku)
}
//logInReelListener?.onLoginBottomSheetDismiss()
}
fun setReelClickedListener(listener : ReelClickedListener){
reelClickedListner = listener
}
interface OnBottomSheetStatusChange {
fun onPDBottomSheetOpened(sku: String?)
fun onPDBottomSheetClose(sku: String?)
}
interface ReelClickedListener{
fun onReelClickedFromPdTray(videoId : Long)
}
}
样式.xml
<!-- Rounded corner BottomSheet-->
<style name="AppBottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog">
<item name="android:windowIsFloating">true</item>
<item name="android:windowSoftInputMode">adjustResize|stateAlwaysVisible</item>
<item name="bottomSheetStyle">@style/AppModalStyle</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
layout_product_detail_bottom_sheet.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/cl_product_detail"
android:layout_height="match_parent"
android:layout_width="match_parent">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_product_detail_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginStart="@dimen/dp_10"
android:layout_marginBottom="@dimen/dp_10"
android:gravity="center">
<LinearLayout
android:layout_width="@dimen/_32dp"
android:layout_height="@dimen/dp_4"
android:layout_gravity="center_horizontal"
android:background="@drawable/shape_purple_round_corner"
android:gravity="center_horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/product_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
ExoPlayer 渲染到提供给它的任何 Surface 中。
您可以通过在您使用的 PlayerView 实例上设置 app:surface_type="texture_view" 来解决此问题。在合成方面,TextureView 比 SurfaceView 更像“普通”视图,因此不太容易出现此类问题。也有一些缺点。
阅读TextureView 的优点和缺点
https://exoplayer.dev/ui-components.html#choosing-a-surface-type