Reputation: 25
I have a Xamarin forms projects and I needed to show videos inside a grid, so I have purchased this video player component: Octane VideoPlayer
and it works well on IOS, but in android it not respect the aspect ratio, many videos are stretched.
I tried a custom render for this video player but nothing changes,and when I put breakpoints I discovered that the code for render is never reached.
Have I missed something ?
example
cs:
public partial class VideoPlayer : ContentPage
{
public VideoPlayerPage()
{
InitializeComponent();
VideoPlayer.Source = "16/9_video.mp4";
}
}
custom render:
[assembly: ExportRenderer(typeof(Octane.Xam.VideoPlayer.VideoPlayer), typeof(Assayil.Droid.VideoPlayerExtRenderer))]
**
public class VideoPlayerExtRenderer : VideoPlayerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Started += (s2, e2) =>
{
UpdateVideoSize();
Control.Player.VideoSizeChanged += (s3, e3) => UpdateVideoSize();
};
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
UpdateVideoSize();
}
private void UpdateVideoSize()
{
if (Element.FillMode == FillMode.Resize)
{
Control.Layout(0, 0, Width, Height);
return;
}
// assume video size = view size if the player has not been loaded yet
var videoWidth = Control.Player?.VideoWidth ?? Width;
var videoHeight = Control.Player?.VideoHeight ?? Height;
var scaleWidth = (double)Width / (double)videoWidth;
var scaleHeight = (double)Height / (double)videoHeight;
double scale;
switch (Element.FillMode)
{
case FillMode.ResizeAspect:
scale = Math.Min(scaleWidth, scaleHeight);
break;
case FillMode.ResizeAspectFill:
scale = Math.Max(scaleWidth, scaleHeight);
break;
default:
// should not happen
scale = 1;
break;
}
var scaledWidth = (int)Math.Round(videoWidth * scale);
var scaledHeight = (int)Math.Round(videoHeight * scale);
// center the video
var l = (Width - scaledWidth) / 2;
var t = (Height - scaledHeight) / 2;
var r = l + scaledWidth;
var b = t + scaledHeight;
Control.Layout(l, t, r, b);
}
}
Upvotes: 1
Views: 1739
Reputation: 63
Placing the VideoPlayer within a Frame, then placing that within StackLayout set to CenterAndExpand for VerticalOptions should do the trick. Works perfectly for Android though you may want to make it platform dependent, it will play with container size in iOS (the video will look fine, but the controller looks better without this fix).
Upvotes: 1
Reputation: 4780
I am the author of the component. This is a well-known issue and I have spent considerable time trying to correct it but unfortunately I have yet to find a stable solution. The most common suggestion comes from a blog which recommends wrapping the VideoView
inside a RelativeLayout
as shown below but doing so yielded no improvement during my testing.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<VideoView android:id="@+id/videoViewRelative"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</VideoView>
</RelativeLayout>
Source: http://blog.kasenlam.com/2012/02/android-how-to-stretch-video-to-fill.html
The code you have pasted above is a workaround that has worked well for some people but again, my testing did not show it to be stable enough for inclusion. As soon as I can identify a proper solution for this I will certainly push it out to all users.
Upvotes: 0