From 2fa6c43615c1bc0a3bbcb5f472ffaeb8ae16a1af Mon Sep 17 00:00:00 2001
From: Olivier Bouillet <62574056+freeboub@users.noreply.github.com>
Date: Mon, 2 Sep 2024 16:13:06 +0200
Subject: [PATCH] fix(android): add subtitleStyle.subtitlesFollowVideo prop to
control subtitles positionning (#4133)
* fix(android): add subtitleStyle.subtitlesFollowVideo prop to control subtitles positionning
* docs: add new prop description
* docs: add supported platform for subtitleStyle
* chore: use constructor instead of parse
---
.../brentvatne/common/api/SubtitleStyle.kt | 6 ++-
.../brentvatne/exoplayer/ExoPlayerView.java | 26 ++++++++++--
docs/pages/component/props.mdx | 41 +++++++++++++++----
examples/basic/src/VideoPlayer.tsx | 1 +
src/specs/VideoNativeComponent.ts | 1 +
src/types/video.ts | 1 +
6 files changed, 63 insertions(+), 13 deletions(-)
diff --git a/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt b/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt
index efb4da0a..1ac0fd03 100644
--- a/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt
+++ b/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt
@@ -6,7 +6,7 @@ import com.facebook.react.bridge.ReadableMap
/**
* Helper file to parse SubtitleStyle prop and build a dedicated class
*/
-class SubtitleStyle private constructor() {
+class SubtitleStyle public constructor() {
var fontSize = -1
private set
var paddingLeft = 0
@@ -19,6 +19,8 @@ class SubtitleStyle private constructor() {
private set
var opacity = 1f
private set
+ var subtitlesFollowVideo = true
+ private set
companion object {
private const val PROP_FONT_SIZE_TRACK = "fontSize"
@@ -27,6 +29,7 @@ class SubtitleStyle private constructor() {
private const val PROP_PADDING_LEFT = "paddingLeft"
private const val PROP_PADDING_RIGHT = "paddingRight"
private const val PROP_OPACITY = "opacity"
+ private const val PROP_SUBTITLES_FOLLOW_VIDEO = "subtitlesFollowVideo"
@JvmStatic
fun parse(src: ReadableMap?): SubtitleStyle {
@@ -37,6 +40,7 @@ class SubtitleStyle private constructor() {
subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0)
subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0)
subtitleStyle.opacity = ReactBridgeUtils.safeGetFloat(src, PROP_OPACITY, 1f)
+ subtitleStyle.subtitlesFollowVideo = ReactBridgeUtils.safeGetBool(src, PROP_SUBTITLES_FOLLOW_VIDEO, true)
return subtitleStyle
}
}
diff --git a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java
index dd18dbfd..45624d6f 100644
--- a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java
+++ b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java
@@ -48,6 +48,8 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE;
private boolean hideShutterView = false;
+ private SubtitleStyle localStyle = new SubtitleStyle();
+
public ExoPlayerView(Context context) {
super(context, null, 0);
@@ -80,10 +82,15 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
adOverlayFrameLayout = new FrameLayout(context);
layout.addView(shutterView, 1, layoutParams);
- layout.addView(adOverlayFrameLayout, 2, layoutParams);
+ if (localStyle.getSubtitlesFollowVideo()) {
+ layout.addView(subtitleLayout, layoutParams);
+ layout.addView(adOverlayFrameLayout, layoutParams);
+ }
addViewInLayout(layout, 0, aspectRatioParams);
- addViewInLayout(subtitleLayout, 1, layoutParams);
+ if (!localStyle.getSubtitlesFollowVideo()) {
+ addViewInLayout(subtitleLayout, 1, layoutParams);
+ }
}
private void clearVideoView() {
@@ -107,7 +114,7 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
}
public void setSubtitleStyle(SubtitleStyle style) {
- // ensure we reset subtile style before reapplying it
+ // ensure we reset subtitle style before reapplying it
subtitleLayout.setUserDefaultStyle();
subtitleLayout.setUserDefaultTextSize();
@@ -121,7 +128,18 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
} else {
subtitleLayout.setVisibility(View.GONE);
}
-
+ if (localStyle.getSubtitlesFollowVideo() != style.getSubtitlesFollowVideo()) {
+ // No need to manipulate layout if value didn't change
+ if (style.getSubtitlesFollowVideo()) {
+ removeViewInLayout(subtitleLayout);
+ layout.addView(subtitleLayout, layoutParams);
+ } else {
+ layout.removeViewInLayout(subtitleLayout);
+ addViewInLayout(subtitleLayout, 1, layoutParams, false);
+ }
+ requestLayout();
+ }
+ localStyle = style;
}
public void setShutterColor(Integer color) {
diff --git a/docs/pages/component/props.mdx b/docs/pages/component/props.mdx
index e3286596..47971ba8 100644
--- a/docs/pages/component/props.mdx
+++ b/docs/pages/component/props.mdx
@@ -846,14 +846,18 @@ source={{
### `subtitleStyle`
-| Property | Description | Platforms |
-| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
-| fontSize | Adjust the font size of the subtitles. Default: font size of the device | Android |
-| paddingTop | Adjust the top padding of the subtitles. Default: 0 | Android |
-| paddingBottom | Adjust the bottom padding of the subtitles. Default: 0 | Android |
-| paddingLeft | Adjust the left padding of the subtitles. Default: 0 | Android |
-| paddingRight | Adjust the right padding of the subtitles. Default: 0 | Android |
-| opacity | Adjust the visibility of subtitles with 0 hiding and 1 fully showing them. Android supports float values between 0 and 1 for varying opacity levels, whereas iOS supports only 0 or 1. Default: 1. | Android, iOS |
+
+
+| Property | Platform | Description | Platforms |
+| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
+| fontSize | Android | Adjust the font size of the subtitles. Default: font size of the device | Android |
+| paddingTop | Android | Adjust the top padding of the subtitles. Default: 0 | Android |
+| paddingBottom | Android | Adjust the bottom padding of the subtitles. Default: 0 | Android |
+| paddingLeft | Android | Adjust the left padding of the subtitles. Default: 0 | Android |
+| paddingRight | Android | Adjust the right padding of the subtitles. Default: 0 | Android |
+| opacity | Android, iOS | Adjust the visibility of subtitles with 0 hiding and 1 fully showing them. Android supports float values between 0 and 1 for varying opacity levels, whereas iOS supports only 0 or 1. Default: 1. | Android, iOS |
+| subtitlesFollowVideo | Android | Boolean to adjust position of subtitles. Default: true |
+
Example:
@@ -861,6 +865,27 @@ Example:
subtitleStyle={{ paddingBottom: 50, fontSize: 20, opacity: 0 }}
```
+Note for `subtitlesFollowVideo`
+
+`subtitlesFollowVideo` helps to determine how the subtitles are positionned.
+To understand this prop you need to understand how views management works.
+The main View style passed to react native video is the position reserved to display the video component.
+It may not match exactly the real video size.
+For exemple, you can pass a 4:3 video view and render a 16:9 video inside.
+So there is a second view, the video view.
+
+Subtitles are managed in a third view.
+
+First react-native-video resize the video to keep aspect ratio (depending on `resizeMode` property) and put it in main view.
+
+* When putting subtitlesFollowVideo to true, the subtitle view will be adapt to the video view.
+It means that if the video is displayed out of screen, the subtitles may also be displayed out of screen.
+
+* When putting subtitlesFollowVideo to false, the subtitle view will keep adapting to the main view.
+It means that if the video is displayed out of screen, the subtitles may also be displayed out of screen.
+
+This prop can be changed on runtime.
+
### `textTracks`
diff --git a/examples/basic/src/VideoPlayer.tsx b/examples/basic/src/VideoPlayer.tsx
index 243d2fa8..b77f97c9 100644
--- a/examples/basic/src/VideoPlayer.tsx
+++ b/examples/basic/src/VideoPlayer.tsx
@@ -268,6 +268,7 @@ const VideoPlayer: FC = ({}) => {
onPlaybackStateChanged={onPlaybackStateChanged}
bufferingStrategy={BufferingStrategyType.DEFAULT}
debug={{enable: true, thread: true}}
+ subtitleStyle={{subtitlesFollowVideo: true}}
/>
)}
diff --git a/src/specs/VideoNativeComponent.ts b/src/specs/VideoNativeComponent.ts
index a5eba10c..82b92745 100644
--- a/src/specs/VideoNativeComponent.ts
+++ b/src/specs/VideoNativeComponent.ts
@@ -131,6 +131,7 @@ type SubtitleStyle = Readonly<{
paddingLeft?: WithDefault;
paddingRight?: WithDefault;
opacity?: WithDefault;
+ subtitlesFollowVideo?: WithDefault;
}>;
type OnLoadData = Readonly<{
diff --git a/src/types/video.ts b/src/types/video.ts
index d29d0108..b34becb5 100644
--- a/src/types/video.ts
+++ b/src/types/video.ts
@@ -168,6 +168,7 @@ export type SubtitleStyle = {
paddingLeft?: number;
paddingRight?: number;
opacity?: number;
+ subtitlesFollowVideo?: boolean;
};
export enum TextTrackType {