0

I am doing video matrix views (1x1-2x2-3x3 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">
                <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>
        </DataTemplate>
    </flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>

On the startup of the matrix views, it displays 4 views (ColumnCount = 2, ToTalRecords = 4) in the view model) and works everytime. Switching to any other views works too. But ocassionaly when switching to 4 views from a single view, there are only 2 new Elements instead of 4 in overrided OnElementChanged. How to ensure to get 4 new Elements everytime?

Please note that this issue doesn't happen when switching to 4 views from 9 views.

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. Is the issue related to the way I use 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);
    }
}
Hong Wang
  • 65
  • 10
  • Occasionally when switching to 4 views from a single view, there are only 2 new Elements instead of 4 in overrided OnElementChanged. See the log. 2020-07-27 12:12:56.PM [DEBUG] OldElement CameraIndex -1, PlayWndHandle 4843540768 2020-07-27 12:12:56.PM [DEBUG] NewElement CameraIndex -1, PlayWndHandle 4640845024 2020-07-27 12:12:56.PM [DEBUG] App.PlayWndHandles[0]: 4640845024 2020-07-27 12:12:56.PM [DEBUG] NewElement CameraIndex -1, PlayWndHandle 4471035856 2020-07-27 12:12:56.PM [DEBUG] App.PlayWndHandles[1]: 4471035856 – Hong Wang Jul 27 '20 at 02:17
  • The method `OnElementChanged` will only been invoked once when the element been loaded . So it will not been invoked if it has existed . So you could re-init the element when you switching to 4 views from a single view . – Lucas Zhang Jul 27 '20 at 07:31
  • @Lucas Zhang Thank you for your suggestion. I have used the following workaround. When switching to 4 views from single view, I init 9 elements first and then reduce it to 4 elements. It appears working. I don't know why just initialising the 4 elements always have 2 new element changed events instead of 4. In the real app. I also have 16 views. Switching to / from any other view size has always working as expected. – Hong Wang Jul 28 '20 at 08:18
  • @Lucas Zhang To better understand the issue, the corresponding Android app screenshots may give you some idea. See the link below. I'd like to let you know that the corresponding Android app doesn't have this issue. But it has a different issue, see https://stackoverflow.com/questions/63130934/xamarin-forms-android-surfaceview-still-video-image-left-behind. Do you have suggestions? – Hong Wang Jul 28 '20 at 09:36
  • Since they are different problems , I will check it sometimes later . For this issue, if you solved it , I will post answer and you could accept it . – Lucas Zhang Jul 28 '20 at 09:38
  • My observation: on decrementing views, ie. removing elements, there will be an OnNewElement event for every element. On incrementing views byadding items, there will be some elements which don't have new element events. – Hong Wang Jul 29 '20 at 05:34
  • I have changed the approach to load flow list view items. 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. It seems this approach is easier than the old way - loading just 4 items first and then adding or removing accordingly. The no. of new element changed events now is 2, 6, 12 and 16 for 1, 4, 9 and 16 views. Why 2, 6, 12 instead of 1, 4 and 9? It seems there is an extra row hidden for the first three? – Hong Wang Jul 31 '20 at 06:49
  • @Lucas Zhang When changing the size of flow list views, actually the flow list control will create new elements every time. 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? See https://stackoverflow.com/questions/63107557/xamarin-forms-ios-uiview-renderer-intermittent-onelementchanged-in-some-cases – Hong Wang Aug 01 '20 at 02:04
  • @Lucas Zhang - MSFT I still haven't resolved this issue. You suggested to reinit the elements. 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. Can you provide more details or sample code on reinitializing the elements? Thank you. Please note that If I switch to a new page on switching view, it works properly. – Hong Wang Oct 06 '20 at 23:49
  • @Lucas Zhang - MSFT I have tried to reinitialize the UIView using Init() of NSObject, Initialize(), or even Dispose() or set to null without success. – Hong Wang Oct 07 '20 at 01:30
  • @Lucas Zhang - MSFT I tried the sample DLToolkit 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? – Hong Wang Oct 07 '20 at 05:13
  • 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. Hope you can help me. – Hong Wang Oct 13 '20 at 03:51

1 Answers1

0

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.

Hong Wang
  • 65
  • 10