asepct ratio fix

This commit is contained in:
tapframe 2025-10-20 14:45:48 +05:30
parent f027788266
commit 415efd4e03
4 changed files with 64 additions and 7 deletions

View file

@ -20,6 +20,7 @@ RCT_EXPORT_VIEW_PROPERTY(allowsExternalPlayback, BOOL)
RCT_EXPORT_VIEW_PROPERTY(usesExternalPlaybackWhileExternalScreenIsActive, BOOL)
RCT_EXPORT_VIEW_PROPERTY(subtitleBottomOffset, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(subtitleFontSize, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString)
// Event properties
RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)

View file

@ -91,6 +91,13 @@ class KSPlayerView: UIView {
updateSubtitleFont(size: size)
}
}
@objc var resizeMode: NSString = "contain" {
didSet {
print("KSPlayerView: [PROP SETTER] resizeMode setter called with value: \(resizeMode)")
applyVideoGravity()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
@ -128,7 +135,10 @@ class KSPlayerView: UIView {
// KSPlayer's subtitleLabel renders internal subtitles
playerView.subtitleLabel.isHidden = false
playerView.subtitleBackView.isHidden = false
playerView.bringSubviewToFront(playerView.subtitleBackView)
// Move subtitle view to main container for independence from video transformations
playerView.subtitleBackView.removeFromSuperview()
self.addSubview(playerView.subtitleBackView)
self.bringSubviewToFront(playerView.subtitleBackView)
print("KSPlayerView: [SETUP] Subtitle views made visible")
print("KSPlayerView: [SETUP] subtitleLabel.isHidden: \(playerView.subtitleLabel.isHidden)")
print("KSPlayerView: [SETUP] subtitleBackView.isHidden: \(playerView.subtitleBackView.isHidden)")
@ -149,7 +159,10 @@ class KSPlayerView: UIView {
private func adjustSubtitlePositioning() {
// Remove existing constraints for subtitle positioning
playerView.subtitleBackView.removeFromSuperview()
playerView.addSubview(playerView.subtitleBackView)
// Add subtitle view to main container (self) instead of playerView to make it independent of video transformations
self.addSubview(playerView.subtitleBackView)
// Ensure subtitles are always on top of video
self.bringSubviewToFront(playerView.subtitleBackView)
// Re-add subtitle label to subtitle back view
playerView.subtitleBackView.addSubview(playerView.subtitleLabel)
@ -159,13 +172,14 @@ class KSPlayerView: UIView {
playerView.subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
// Store the bottom constraint reference for dynamic updates
subtitleBottomConstraint = playerView.subtitleBackView.bottomAnchor.constraint(equalTo: playerView.bottomAnchor, constant: -CGFloat(subtitleBottomOffset.floatValue))
// Constrain to main container (self) instead of playerView to make subtitles independent of video transformations
subtitleBottomConstraint = playerView.subtitleBackView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -CGFloat(subtitleBottomOffset.floatValue))
NSLayoutConstraint.activate([
// Position subtitles using dynamic offset from React Native
subtitleBottomConstraint!,
playerView.subtitleBackView.centerXAnchor.constraint(equalTo: playerView.centerXAnchor),
playerView.subtitleBackView.widthAnchor.constraint(lessThanOrEqualTo: playerView.widthAnchor, constant: -20),
playerView.subtitleBackView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
playerView.subtitleBackView.widthAnchor.constraint(lessThanOrEqualTo: self.widthAnchor, constant: -20),
playerView.subtitleBackView.heightAnchor.constraint(lessThanOrEqualToConstant: 100),
// Subtitle label constraints within the back view
@ -200,6 +214,30 @@ class KSPlayerView: UIView {
}
}
}
private func applyVideoGravity() {
print("KSPlayerView: [VIDEO GRAVITY] Applying resizeMode: \(resizeMode)")
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
let contentMode: UIViewContentMode
switch self.resizeMode.lowercased {
case "cover":
contentMode = .scaleAspectFill
case "stretch":
contentMode = .scaleToFill
case "contain":
contentMode = .scaleAspectFit
default:
contentMode = .scaleAspectFit
}
// Set contentMode on the player itself, not the view
self.playerView.playerLayer?.player.contentMode = contentMode
print("KSPlayerView: [VIDEO GRAVITY] Set player contentMode to: \(contentMode)")
}
}
private func setupPlayerCallbacks() {
// Configure KSOptions (use static defaults where required)
@ -275,6 +313,9 @@ class KSPlayerView: UIView {
if let playerLayer = playerView.playerLayer {
playerLayer.delegate = self
print("KSPlayerView: Delegate set successfully on playerLayer")
// Apply video gravity after player is set up
applyVideoGravity()
} else {
print("KSPlayerView: ERROR - playerLayer is nil, cannot set delegate")
}
@ -546,7 +587,11 @@ class KSPlayerView: UIView {
} else if trackId == -1 {
// Disable all subtitles
for track in textTracks { track.isEnabled = false }
print("KSPlayerView: Disabled all text tracks")
// Clear srtControl selection and hide subtitle views
self.playerView.srtControl.selectedSubtitleInfo = nil
self.playerView.subtitleLabel.isHidden = true
self.playerView.subtitleBackView.isHidden = true
print("KSPlayerView: Disabled all text tracks and cleared srtControl selection")
} else {
print("KSPlayerView: Text track \(trackId) not found. Available track IDs: \(textTracks.map { Int($0.trackID) }), array indices: 0..\(textTracks.count - 1)")
}

View file

@ -16,6 +16,7 @@ interface KSPlayerViewProps {
usesExternalPlaybackWhileExternalScreenIsActive?: boolean;
subtitleBottomOffset?: number;
subtitleFontSize?: number;
resizeMode?: 'contain' | 'cover' | 'stretch';
onLoad?: (data: any) => void;
onProgress?: (data: any) => void;
onBuffering?: (data: any) => void;
@ -52,6 +53,7 @@ export interface KSPlayerProps {
usesExternalPlaybackWhileExternalScreenIsActive?: boolean;
subtitleBottomOffset?: number;
subtitleFontSize?: number;
resizeMode?: 'contain' | 'cover' | 'stretch';
onLoad?: (data: any) => void;
onProgress?: (data: any) => void;
onBuffering?: (data: any) => void;
@ -177,6 +179,7 @@ const KSPlayer = forwardRef<KSPlayerRef, KSPlayerProps>((props, ref) => {
usesExternalPlaybackWhileExternalScreenIsActive={props.usesExternalPlaybackWhileExternalScreenIsActive}
subtitleBottomOffset={props.subtitleBottomOffset}
subtitleFontSize={props.subtitleFontSize}
resizeMode={props.resizeMode}
onLoad={(e: any) => props.onLoad?.(e?.nativeEvent ?? e)}
onProgress={(e: any) => props.onProgress?.(e?.nativeEvent ?? e)}
onBuffering={(e: any) => props.onBuffering?.(e?.nativeEvent ?? e)}

View file

@ -1315,6 +1315,12 @@ const KSPlayerCore: React.FC = () => {
};
const cycleAspectRatio = () => {
// iOS KSPlayer: toggle native resize mode so subtitles remain independent
if (Platform.OS === 'ios') {
setResizeMode((prev) => (prev === 'cover' ? 'contain' : 'cover'));
return;
}
// Fallback (noniOS paths): keep legacy zoom behavior
const newZoom = zoomScale === 1.1 ? 1 : 1.1;
setZoomScale(newZoom);
setZoomTranslateX(0);
@ -2717,7 +2723,7 @@ const KSPlayerCore: React.FC = () => {
>
<KSPlayerComponent
ref={ksPlayerRef}
style={[styles.video, customVideoStyles, { transform: [{ scale: zoomScale }] }]}
style={styles.video}
source={{
uri: currentStreamUrl,
headers: headers && Object.keys(headers).length > 0 ? headers : undefined
@ -2730,6 +2736,7 @@ const KSPlayerCore: React.FC = () => {
usesExternalPlaybackWhileExternalScreenIsActive={true}
subtitleBottomOffset={subtitleBottomOffset}
subtitleFontSize={subtitleSize}
resizeMode={resizeMode === 'none' ? 'contain' : resizeMode}
onProgress={handleProgress}
onLoad={onLoad}
onEnd={onEnd}
@ -2762,6 +2769,7 @@ const KSPlayerCore: React.FC = () => {
skip={skip}
handleClose={handleClose}
cycleAspectRatio={cycleAspectRatio}
currentResizeMode={resizeMode}
setShowAudioModal={setShowAudioModal}
setShowSubtitleModal={setShowSubtitleModal}
isSubtitleModalOpen={showSubtitleModal}