I am doing video matrix views (1x1, 2x2, 3x3 and 4x4 views) using FlowListView. For iOS app, UIView renderer is used to integrate with a third party video SDK. Here is the FlowListView.
` <flv:FlowListView x:Name="VideoFlowList" FlowColumnCount="{Binding ColumnCount}" RowHeight="{Binding RowHeight, Mode=TwoWay}"
SeparatorVisibility="None" HasUnevenRows="false" BackgroundColor="Transparent"
FlowColumnMinWidth="80" FlowTotalRecords="{Binding TotalRecords, Mode=TwoWay}" FlowItemsSource="{Binding Items}">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid x:Name="VideoGrid" Padding="2" BackgroundColor="{Binding SelectedBorderColour, Mode=TwoWay}" RowSpacing="1" ColumnSpacing="1"
IsVisible="{Binding Visible}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<video:CameraView x:Name="MyCameraView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="Black" />
<Image x:Name="AddIcon" Source="panel_add.png" Grid.Row="0" Grid.Column="0" IsVisible="{Binding CameraNotAssigned}"
HorizontalOptions="Center" VerticalOptions="Center" Aspect="AspectFit" BackgroundColor="Transparent" WidthRequest="50" HeightRequest="50">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.AddCameraCommand, Source={x:Reference BrowseItemsPage}}"
CommandParameter="{x:Reference VideoGrid}" NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<Label x:Name="Label" HorizontalOptions="Fill" HorizontalTextAlignment="Center" VerticalOptions="End"
BackgroundColor="Silver" Opacity="0.5" Text="{Binding CameraName, Mode=TwoWay}" TextColor="Black"/>
<!--<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.VideoGridTappedCommand, Source={x:Reference BrowseItemsPage}}"
CommandParameter="{x:Reference VideoGrid}" NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>-->
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>`
Here is the code of the ViewRenderer.
`public class VideoRender : ViewRenderer<CameraView, UIVideoView>
{
private UIVideoView _videoView;
protected override void OnElementChanged(ElementChangedEventArgs<CameraView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
//Unsubscribe
_videoView.Tapped -= OnVideoViewTapped;
Log.Debug($"OldElement CameraIndex {e.OldElement.CameraIndex}, PlayWndHandle {e.OldElement.PlayWndHandle}");
}
if (e.NewElement != null)
{
//Control is TNativeView, CameraView
if (Control == null)
{
_videoView = new UIVideoView(Element);
SetNativeControl(_videoView);
}
//Element.PlayWndHandle = Handle;
if (_videoView.Subviews.Length > 0)
{
Element.PlayWndHandle = _videoView.Subviews[0].Handle;
}
App.PlayWndHandles.Add(Element.PlayWndHandle);
Log.Debug($"NewElement CameraIndex {Element.CameraIndex}, PlayWndHandle {Element.PlayWndHandle}");
Log.Debug($"App.PlayWndHandles[{App.PlayWndHandles.Count - 1}]: {Element.PlayWndHandle}");
// Subscribe
_videoView.Tapped += OnVideoViewTapped;
}
}
}`
I added a subview in the UIView / UIVideoView and play the video in the subview.
void Initialize() { //place the video in subview var subView = new UIView(); subView.UserInteractionEnabled = true; AddSubview(subView); if (Subviews.Length > 0) { Subviews[0].Frame = new CoreGraphics.CGRect(0, 0, 100, 100); } }
I load all 16 items first. Then I use visibility binding to show / hide the items based on the the number of views in the matrix. The number of new elements from OnElementChanged events is 2, 6, 12 and 16 for 1, 4, 9 and 16 views respectively. Why 2, 6, 12 instead of 1, 4 and 9? It seems there is an extra row hidden for the first three?
Please note that the number of surface holders created with Android surface view is always correct each time. When switching to 1, 4, 9 and 16 views, there are 1, 4, 9 and 16 surface holders created respectively.
This approach is easier than loading just 4 items first and then adding or removing accordingly. See Xamarin forms iOS UIView Renderer intermittent OnElementChanged in some cases: https://stackoverflow.com/questions/63107557/xamarin-forms-ios-uiview-renderer-intermittent-onelementchanged-in-some-cases
I am doing video matrix views (1x1, 2x2, 3x3 and 4x4 views) using FlowListView. For iOS app, UIView renderer is used to integrate with a third party video SDK. Here is the FlowListView.
` <flv:FlowListView x:Name="VideoFlowList" FlowColumnCount="{Binding ColumnCount}" RowHeight="{Binding RowHeight, Mode=TwoWay}"
SeparatorVisibility="None" HasUnevenRows="false" BackgroundColor="Transparent"
FlowColumnMinWidth="80" FlowTotalRecords="{Binding TotalRecords, Mode=TwoWay}" FlowItemsSource="{Binding Items}">
Here is the code of the ViewRenderer.
`public class VideoRender : ViewRenderer<CameraView, UIVideoView>
{
private UIVideoView _videoView;
}`
I added a subview in the UIView / UIVideoView and play the video in the subview.
void Initialize() { //place the video in subview var subView = new UIView(); subView.UserInteractionEnabled = true; AddSubview(subView); if (Subviews.Length > 0) { Subviews[0].Frame = new CoreGraphics.CGRect(0, 0, 100, 100); } }I load all 16 items first. Then I use visibility binding to show / hide the items based on the the number of views in the matrix. The number of new elements from OnElementChanged events is 2, 6, 12 and 16 for 1, 4, 9 and 16 views respectively. Why 2, 6, 12 instead of 1, 4 and 9? It seems there is an extra row hidden for the first three?
Please note that the number of surface holders created with Android surface view is always correct each time. When switching to 1, 4, 9 and 16 views, there are 1, 4, 9 and 16 surface holders created respectively.
This approach is easier than loading just 4 items first and then adding or removing accordingly. See Xamarin forms iOS UIView Renderer intermittent OnElementChanged in some cases: https://stackoverflow.com/questions/63107557/xamarin-forms-ios-uiview-renderer-intermittent-onelementchanged-in-some-cases