Fix: Fixed regression in 1.4.2 where stretch, contain, and cover buttons would not function and video playback would default to stretch

This commit is contained in:
LivinDuck 2026-03-14 00:54:27 +08:00
parent dd6b0ffb46
commit 4e40306de1
2 changed files with 138 additions and 1683 deletions

View file

@ -18,7 +18,6 @@ import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.CaptionStyleCompat import androidx.media3.ui.CaptionStyleCompat
import androidx.media3.ui.DefaultTimeBar
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
import androidx.media3.ui.SubtitleView import androidx.media3.ui.SubtitleView
import com.brentvatne.common.api.ResizeMode import com.brentvatne.common.api.ResizeMode
@ -115,20 +114,19 @@ class ExoPlayerView @JvmOverloads constructor(context: Context, attrs: Attribute
fun setResizeMode(@ResizeMode.Mode mode: Int) { fun setResizeMode(@ResizeMode.Mode mode: Int) {
val resizeMode = when (mode) { val resizeMode = when (mode) {
ResizeMode.RESIZE_MODE_FIT -> androidx.media3.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT ResizeMode.RESIZE_MODE_FIT -> AspectRatioFrameLayout.RESIZE_MODE_FIT
ResizeMode.RESIZE_MODE_FIXED_WIDTH -> androidx.media3.ui.AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH ResizeMode.RESIZE_MODE_FIXED_WIDTH -> AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH
ResizeMode.RESIZE_MODE_FIXED_HEIGHT -> androidx.media3.ui.AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT ResizeMode.RESIZE_MODE_FIXED_HEIGHT -> AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT
ResizeMode.RESIZE_MODE_FILL -> androidx.media3.ui.AspectRatioFrameLayout.RESIZE_MODE_FILL ResizeMode.RESIZE_MODE_FILL -> AspectRatioFrameLayout.RESIZE_MODE_FILL
ResizeMode.RESIZE_MODE_CENTER_CROP -> androidx.media3.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM ResizeMode.RESIZE_MODE_CENTER_CROP -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
else -> androidx.media3.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT else -> AspectRatioFrameLayout.RESIZE_MODE_FIT
}
if (playerView.width > 0 && playerView.height > 0) {
playerView.resizeMode = resizeMode
} else {
pendingResizeMode = resizeMode
} }
// Re-assert subtitle rendering mode for the current style. playerView.resizeMode = resizeMode
pendingResizeMode = resizeMode
playerView.requestLayout()
requestLayout()
updateSubtitleRenderingMode() updateSubtitleRenderingMode()
applySubtitleStyle(localStyle) applySubtitleStyle(localStyle)
} }
@ -349,15 +347,15 @@ class ExoPlayerView @JvmOverloads constructor(context: Context, attrs: Attribute
} }
fun invalidateAspectRatio() { fun invalidateAspectRatio() {
playerView.post { pendingResizeMode?.let { resizeMode ->
playerView.requestLayout() playerView.resizeMode = resizeMode
} }
playerView.requestLayout()
requestLayout()
} }
private val playerListener = object : Player.Listener { private val playerListener = object : Player.Listener {
override fun onCues(cueGroup: CueGroup) { override fun onCues(cueGroup: CueGroup) {
// Keep overlay subtitles in sync. This does NOT interfere with PlayerView's own subtitle rendering.
// When subtitlesFollowVideo=false, overlaySubtitleView is the visible one.
updateSubtitleRenderingMode() updateSubtitleRenderingMode()
overlaySubtitleView.setCues(cueGroup.cues) overlaySubtitleView.setCues(cueGroup.cues)
} }
@ -365,19 +363,47 @@ class ExoPlayerView @JvmOverloads constructor(context: Context, attrs: Attribute
override fun onTimelineChanged(timeline: Timeline, reason: Int) { override fun onTimelineChanged(timeline: Timeline, reason: Int) {
playerView.post { playerView.post {
playerView.requestLayout() playerView.requestLayout()
pendingResizeMode?.let { resizeMode ->
playerView.resizeMode = resizeMode
} }
} }
} }
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { override fun onEvents(player: Player, events: Player.Events) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec) if (events.contains(Player.EVENT_VIDEO_SIZE_CHANGED)) {
val width = MeasureSpec.getSize(widthMeasureSpec) pendingResizeMode?.let { resizeMode ->
val height = MeasureSpec.getSize(heightMeasureSpec) playerView.resizeMode = resizeMode
if (width > 0 && height > 0) { }
playerView.requestLayout()
requestLayout()
}
}
}
/**
* React Native (Yoga) can defer layout passes that PlayerView needs for its
* child views. This forces a second measure/layout after RN finishes, ensuring
* internal views receive the final size.
*/
private val layoutRunnable = Runnable {
measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
)
layout(left, top, right, bottom)
}
override fun requestLayout() {
super.requestLayout()
post(layoutRunnable)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (changed) {
pendingResizeMode?.let { resizeMode -> pendingResizeMode?.let { resizeMode ->
playerView.resizeMode = resizeMode playerView.resizeMode = resizeMode
} }
// Re-apply bottomPaddingFraction once we have a concrete height.
updateSubtitleRenderingMode() updateSubtitleRenderingMode()
applySubtitleStyle(localStyle) applySubtitleStyle(localStyle)
} }

File diff suppressed because it is too large Load diff