Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extra new elements from OnElementChanged in UIView on iOS #293

Open
j2bmw opened this issue Aug 1, 2020 · 6 comments
Open

Extra new elements from OnElementChanged in UIView on iOS #293

j2bmw opened this issue Aug 1, 2020 · 6 comments

Comments

@j2bmw
Copy link

j2bmw commented Aug 1, 2020

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

@j2bmw
Copy link
Author

j2bmw commented Aug 1, 2020

Screenshot_20200728-153012

@j2bmw
Copy link
Author

j2bmw commented Oct 7, 2020

I tried to clear all ItemsSource items and then add new items. But the problem remains. It seems clearing / reinitializing biding items doesn't help. Please note that If I open a new page on changing view size, it works properly. I also tried to reinitialize the UIView using Init() of NSObject, Initialize(), or even Dispose() or set to null without success.

@j2bmw
Copy link
Author

j2bmw commented Oct 7, 2020

I tried the sample SimpleGalleryPage and observed similar behaviour. If I remove to n items, only these items have FlowItemDisappearing visibility changed events. I want all items have the disappearing event hence all will be new elements in iOS ViewRenderer after adding more items later. Is this possible? @daniel-luberda, can you please shed light on this?

@j2bmw
Copy link
Author

j2bmw commented Oct 13, 2020

@daniel-luberda, I believe you can offer your helping hand. I've stuck with this issue for long time.

In Android app, when changing the size of the matrix view, each view element / cell, regardless of the size, does FlowItemDisappearing and then FlowItemAppearing consistently. That's what we want to achieve the same on iOS app.

iOS app's behaviour is different, only some elements in the matrix view do disappearing and appearing. How can I change this behaviour?

@j2bmw
Copy link
Author

j2bmw commented Oct 14, 2020

In my iOS app, I compared the events in OnElementChanged in the renderer with the events in FlowItemDisappearing and FlowItemAppearing, and found discrepancies between them. For

example, after changing matrix size from 3x3 to 1 and then from 1 to 3x3, the following is observed:
In OnElementChanged:
3x3-1: deleted first row, added new element 1, OK

1-3x3: recreated the elements 6-9 in 3rd row. The problems: 1. shouldn't need to update 3rd row; 2. the handles of element 2 and 3 were not updated, remaining 0.

3x3-1: deleted the elements in 2nd row. The video plays OK in single view. But the problem is now the handles for elements 2-6 become 0. It will be a problem for next transition 1-9.

In FlowListItem appearing / disappearing events:

3x3-1: disappearing view index 0-2 and appearing 0 (new element 1), correct

1-3x3: -(3-5), +(0-2), -(6,8), +(3-5), +(6-8), this says new elements in row 1, recreated elements in row 2 and 3. The problem: it doesn't match the events in OnElementChanged. It

appears OnElementChanged missed events.

3x3-1: -(0-2), +(0) new element 1, correct

My problem is the handles of the sub views will go out of sync at the end. If each view element / cell in the new matrix disappears and then appears, there will be no problem at all.

Every tile will be refreshed.

@j2bmw
Copy link
Author

j2bmw commented Oct 16, 2020

It appears that using 4 separate lists of play window handles (one for each matrix size) can overcome the handle management issue. A single view is specially handled by clearing the handles in the list because the handle will always be removed and re-created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant