Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Bug] CarouselView is caching elements when its ItemTemplate contains multiple elements and has SkiaSharp drawings #10656

Closed
Juansero29 opened this issue May 12, 2020 · 2 comments

Comments

@Juansero29
Copy link

Juansero29 commented May 12, 2020

Description

I have a custom control which is intended to be a calendar. It uses a CarouselView.

To designate the selected day, I draw a blue circle around the selected day and another one around the current day (using the SKCanvasView from SkiaSharp). Then, the user can swipe left or right to navigate through each week of the calendar and select some of the days.

Problem is: when swiping multiple weeks, we can see that the blue circle is drawing itself on days that haven't been selected before and that the CarouselView is somehow caching some of the graphical controls used to recreate these days. This problem is there on iOS and Android.

I also have a button for the user to go to the current date in the calendar, which also causes some unexpected behavior with the blue circles.

We can see the problem with the gif below.

Steps to Reproduce

  1. Declare a CarouselView in XAML
  2. Set its ItemSource to a List of Lists with more than 10 elements (can vary depending on the device, so just insert a considerable amount of elements).
  3. In the ItemTemplate of this CarouselView, use a SKCanvas or Frame to draw something on some of the elements inside the ItemTemplate.
  4. Launch the app, and see how the drawing gets reused on some of the views inside of the CarouselView where it wasn't supposed to be.

Expected Behavior

The views shouldn't be cached/recycled, or at least there should be a parameter to tell if we want this to happen or not.

Actual Behavior

The CarouselView caches/recycles/reuses some of the graphic elements

Basic Information

  • Version with issue: 4.6.0.726

  • Last known good version: No known good version (tried backtracking to XF 4.3.0.947036 and SkiaSharp.Views.Forms 1.68.0, they also report the same behavior)

  • IDE: Microsoft Visual Studio Enterprise 2019 Version 16.5.3

  • Platform Target Frameworks: Xamarin.Forms

    • iOS: Building Agains iOS 13.4 with Xamarin.iOS and Xamarin.Mac SDK 13.16.0.13 (b75deaf)
    • Android: Building against Android 9.0 API 28 with Xamarin.Android SDK 10.2.0.100 (d16-5/988c811)
  • NuGet Packages: SkiaSharp.Views.Forms 1.68.2.1, Xamarin.Forms 4.6.0.726

  • Affected Devices: all

Screenshots

Deselection when choosing a new day isn't supposed to work in this reproduction project, even though it is managed in the control used in the app.

Android:
carouselviewcaching

iOS:
carouselviewcachingios

Reproduction Link

CarouselViewCaching.zip

This is the project shown in the gif. With a simplified version of my calendar, and multiple comments.

The CarouselView is in the MainPage.xaml, the ItemSource is assigned in the "OnAppearing" override in code-behind (MainPage.xaml.cs) to simplify the code and the SKCanvasView are in the "DayCell.xaml" file, which uses simple logic to make the "SelectedDayCanvasView" canvas visible when the day is tapped and the "CurrentDayCanvasView" to the day that has the property "IsCurrentDay" set to true when the BindingContext changes.

          <!--#region Caching CarouselView-->
            <CarouselView
                    x:Name="CarouselView"
                    Grid.Row="1"
                    VerticalOptions="FillAndExpand"
                    IsScrollAnimated="False">

                <CarouselView.ItemTemplate>
                    <DataTemplate>
                        <Grid x:Name="daysGrid">

                            <Grid.RowDefinitions>
                                <RowDefinition Height="70" />
                            </Grid.RowDefinitions>

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition />
                                <ColumnDefinition />
                                <ColumnDefinition />
                                <ColumnDefinition />
                                <ColumnDefinition />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>

                            <!--The expression ".[int]" simply tells that the binding context is the element "int" of the current list, as this is a list of lists.-->
                            <controls:DayCell Grid.Column="0" BindingContext="{Binding .[0]}" />
                            <controls:DayCell Grid.Column="1" BindingContext="{Binding .[1]}" />
                            <controls:DayCell Grid.Column="2" BindingContext="{Binding .[2]}" />
                            <controls:DayCell Grid.Column="3" BindingContext="{Binding .[3]}" />
                            <controls:DayCell Grid.Column="4" BindingContext="{Binding .[4]}" />
                            <controls:DayCell Grid.Column="5" BindingContext="{Binding .[5]}" />
                            <controls:DayCell Grid.Column="6" BindingContext="{Binding .[6]}" />

                        </Grid>
                    </DataTemplate>
                </CarouselView.ItemTemplate>
            </CarouselView>
            <!--#endregion-->

Workaround

I found a workaround but it's specific to my project and it doesn't work all the time. In the SKCanvasView_PaintSurface methods, I checked if the day drown is selected using an "IsSelected" property and also the "IsCurrentDay" before drawing the current day circle. However, sometimes I also get the BindingContext of the cached view, which makes the bug reappear.

@Juansero29 Juansero29 added s/unverified New report that has yet to be verified t/bug 🐛 labels May 12, 2020
@Juansero29 Juansero29 changed the title [Bug] CarouselView is caching elements when it's ItemTemplate contains multiple elements and has SkiaSharp drawings [Bug] CarouselView is caching elements when its ItemTemplate contains multiple elements and has SkiaSharp drawings May 12, 2020
@Juansero29
Copy link
Author

Further tests confirmed what I first thought: the problem doesn't come from the SKCanvasView, I changed it to use a Frame (native Xamarin.Forms control). It has a different style because I couldn't make a circle with it, but the same problem persists as shown here:

problemisntskiasharp

This test sample can be found here:
CarouselViewCachingNoSkiaSharp.zip

@rmarinho
Copy link
Member

Duplicated of #9200

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

No branches or pull requests

3 participants