Skip to content

Extra new elements from OnElementChanged in UIView on iOS #293

@j2bmw

Description

@j2bmw

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions