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
This commit is contained in:
parent
688d98d68f
commit
2fa6c43615
@ -6,7 +6,7 @@ import com.facebook.react.bridge.ReadableMap
|
|||||||
/**
|
/**
|
||||||
* Helper file to parse SubtitleStyle prop and build a dedicated class
|
* Helper file to parse SubtitleStyle prop and build a dedicated class
|
||||||
*/
|
*/
|
||||||
class SubtitleStyle private constructor() {
|
class SubtitleStyle public constructor() {
|
||||||
var fontSize = -1
|
var fontSize = -1
|
||||||
private set
|
private set
|
||||||
var paddingLeft = 0
|
var paddingLeft = 0
|
||||||
@ -19,6 +19,8 @@ class SubtitleStyle private constructor() {
|
|||||||
private set
|
private set
|
||||||
var opacity = 1f
|
var opacity = 1f
|
||||||
private set
|
private set
|
||||||
|
var subtitlesFollowVideo = true
|
||||||
|
private set
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val PROP_FONT_SIZE_TRACK = "fontSize"
|
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_LEFT = "paddingLeft"
|
||||||
private const val PROP_PADDING_RIGHT = "paddingRight"
|
private const val PROP_PADDING_RIGHT = "paddingRight"
|
||||||
private const val PROP_OPACITY = "opacity"
|
private const val PROP_OPACITY = "opacity"
|
||||||
|
private const val PROP_SUBTITLES_FOLLOW_VIDEO = "subtitlesFollowVideo"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun parse(src: ReadableMap?): SubtitleStyle {
|
fun parse(src: ReadableMap?): SubtitleStyle {
|
||||||
@ -37,6 +40,7 @@ class SubtitleStyle private constructor() {
|
|||||||
subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0)
|
subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0)
|
||||||
subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0)
|
subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0)
|
||||||
subtitleStyle.opacity = ReactBridgeUtils.safeGetFloat(src, PROP_OPACITY, 1f)
|
subtitleStyle.opacity = ReactBridgeUtils.safeGetFloat(src, PROP_OPACITY, 1f)
|
||||||
|
subtitleStyle.subtitlesFollowVideo = ReactBridgeUtils.safeGetBool(src, PROP_SUBTITLES_FOLLOW_VIDEO, true)
|
||||||
return subtitleStyle
|
return subtitleStyle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,8 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE;
|
private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE;
|
||||||
private boolean hideShutterView = false;
|
private boolean hideShutterView = false;
|
||||||
|
|
||||||
|
private SubtitleStyle localStyle = new SubtitleStyle();
|
||||||
|
|
||||||
public ExoPlayerView(Context context) {
|
public ExoPlayerView(Context context) {
|
||||||
super(context, null, 0);
|
super(context, null, 0);
|
||||||
|
|
||||||
@ -80,10 +82,15 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
adOverlayFrameLayout = new FrameLayout(context);
|
adOverlayFrameLayout = new FrameLayout(context);
|
||||||
|
|
||||||
layout.addView(shutterView, 1, layoutParams);
|
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(layout, 0, aspectRatioParams);
|
||||||
addViewInLayout(subtitleLayout, 1, layoutParams);
|
if (!localStyle.getSubtitlesFollowVideo()) {
|
||||||
|
addViewInLayout(subtitleLayout, 1, layoutParams);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearVideoView() {
|
private void clearVideoView() {
|
||||||
@ -107,7 +114,7 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSubtitleStyle(SubtitleStyle style) {
|
public void setSubtitleStyle(SubtitleStyle style) {
|
||||||
// ensure we reset subtile style before reapplying it
|
// ensure we reset subtitle style before reapplying it
|
||||||
subtitleLayout.setUserDefaultStyle();
|
subtitleLayout.setUserDefaultStyle();
|
||||||
subtitleLayout.setUserDefaultTextSize();
|
subtitleLayout.setUserDefaultTextSize();
|
||||||
|
|
||||||
@ -121,7 +128,18 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
|
|||||||
} else {
|
} else {
|
||||||
subtitleLayout.setVisibility(View.GONE);
|
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) {
|
public void setShutterColor(Integer color) {
|
||||||
|
@ -846,14 +846,18 @@ source={{
|
|||||||
|
|
||||||
### `subtitleStyle`
|
### `subtitleStyle`
|
||||||
|
|
||||||
| Property | Description | Platforms |
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
|
|
||||||
| fontSize | Adjust the font size of the subtitles. Default: font size of the device | Android |
|
| Property | Platform | Description | Platforms |
|
||||||
| paddingTop | Adjust the top padding of the subtitles. Default: 0 | Android |
|
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
|
||||||
| paddingBottom | Adjust the bottom padding of the subtitles. Default: 0 | Android |
|
| fontSize | Android | Adjust the font size of the subtitles. Default: font size of the device | Android |
|
||||||
| paddingLeft | Adjust the left padding of the subtitles. Default: 0 | Android |
|
| paddingTop | Android | Adjust the top padding of the subtitles. Default: 0 | Android |
|
||||||
| paddingRight | Adjust the right padding of the subtitles. Default: 0 | Android |
|
| paddingBottom | Android | Adjust the bottom 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 |
|
| 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:
|
Example:
|
||||||
|
|
||||||
@ -861,6 +865,27 @@ Example:
|
|||||||
subtitleStyle={{ paddingBottom: 50, fontSize: 20, opacity: 0 }}
|
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`
|
### `textTracks`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
@ -268,6 +268,7 @@ const VideoPlayer: FC<Props> = ({}) => {
|
|||||||
onPlaybackStateChanged={onPlaybackStateChanged}
|
onPlaybackStateChanged={onPlaybackStateChanged}
|
||||||
bufferingStrategy={BufferingStrategyType.DEFAULT}
|
bufferingStrategy={BufferingStrategyType.DEFAULT}
|
||||||
debug={{enable: true, thread: true}}
|
debug={{enable: true, thread: true}}
|
||||||
|
subtitleStyle={{subtitlesFollowVideo: true}}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
|
@ -131,6 +131,7 @@ type SubtitleStyle = Readonly<{
|
|||||||
paddingLeft?: WithDefault<Float, 0>;
|
paddingLeft?: WithDefault<Float, 0>;
|
||||||
paddingRight?: WithDefault<Float, 0>;
|
paddingRight?: WithDefault<Float, 0>;
|
||||||
opacity?: WithDefault<Float, 1>;
|
opacity?: WithDefault<Float, 1>;
|
||||||
|
subtitlesFollowVideo?: WithDefault<boolean, true>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type OnLoadData = Readonly<{
|
type OnLoadData = Readonly<{
|
||||||
|
@ -168,6 +168,7 @@ export type SubtitleStyle = {
|
|||||||
paddingLeft?: number;
|
paddingLeft?: number;
|
||||||
paddingRight?: number;
|
paddingRight?: number;
|
||||||
opacity?: number;
|
opacity?: number;
|
||||||
|
subtitlesFollowVideo?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum TextTrackType {
|
export enum TextTrackType {
|
||||||
|
Loading…
Reference in New Issue
Block a user