C1Calendar performance Android

Posted by: b.posthumus on 27 September 2017, 11:39 pm EST

  • Posted 27 September 2017, 11:39 pm EST

    I’m using the C1 calendar component in a Xamarin Forms app to display someones schedule. This is done by displaying colors which represent different schedule types.

    On iOS the page with the calendar performs as It should but on Android the performance is very poor. I’ve stripped most unnecessary markup from the page and only enable 6 months in the future and past to improve performance but It’s still way to slow. The colorcodes I get from a webservice, but I store this data in a local database to avoid multiple calls to the webservice, also to increase performance. The data then gets updated once a day.

    Even navigating to the page is very slow, I’m using a MasterDetail page structure and when I click the link which navigates me to the detail page which holds the calendar It takes 2 seconds for the page to display and then the rendering of the component still has to be done. Even after the calendar has rendered navigating to another month/year is very sluggish.

    Is there any way I can improve the performance of the calendar component?

    • "
      • “Rendering of the calendar is slow”

      • “Navigating in the calendar is slow (Switching months/years)”

    "

    C1.Android.Calendar version: v2.3.20172.189

    Xamarin Forms version: v2.3.4.270

    XAML

    
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
                 xmlns:c1="clr-namespace:C1.Xamarin.Forms.Calendar;assembly=C1.Xamarin.Forms.Calendar"        
                 xmlns:controls="clr-namespace:UIBApp.Controls;assembly=UIBApp"
                 xmlns:converters="clr-namespace:UIBApp.Converters;assembly=UIBApp"
                 x:Class="UIBApp.Views.PlanboardPage"
                 Title="Planbord">
        <ContentPage.Resources>
            <ResourceDictionary>
                <converters:NegateBooleanConverter x:Key="inverter"/>
            </ResourceDictionary>
        </ContentPage.Resources>
        <ContentPage.Content>
            <StackLayout>
                <ActivityIndicator Grid.Row="0" Color="#14437b" IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}" Margin="0,15"/>
    
                <c1:C1Calendar                     
                    x:Name="calendar" 
                    VerticalOptions="FillAndExpand"                
                    BackgroundColor="White"
                    FontSize="12"
                    HeaderFontSize="16"
                    DayOfWeekBackgroundColor="#eaeef3"
                    TextColor="Black"
                    TodayFontAttributes="Bold"
                    MaxSelectionCount="1"                    
                    SelectionChanged="OnSelectionChanged"
                    HeaderTextColor="#14437b"
                    SelectionBackgroundColor="#5C8DC7"
                    SelectionTextColor="White"  
                    IsVisible="{Binding IsBusy, Converter={StaticResource inverter}}"
                >
                    <c1:C1Calendar.DaySlotTemplate>
                        <DataTemplate>                       
                            <Grid HorizontalOptions="FillAndExpand" VerticalOptions="Center">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="8" />
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="1*" />
                                </Grid.ColumnDefinitions>
                                <Label Grid.Row="0" Grid.Column="0" Text="{Binding Day}" Margin="0,18,0,0" HorizontalTextAlignment="Center" HorizontalOptions="FillAndExpand" VerticalOptions="Center" FontSize="12"/>
                                
                                <controls:ColorCodeRepeater ItemsSource="{Binding ColorCodes}" 
                                                            BackgroundColor="Transparent"                                                             
                                                            Margin="{Binding Margin}"
                                                            WidthRequest="8"
                                                            Rotation="270"                                                             
                                                            HorizontalOptions="Center"
                                                            VerticalOptions="FillAndExpand"
                                                            Grid.Row="1"
                                                            Grid.Column="0">
                                    <controls:ColorCodeRepeater.ItemTemplate>
                                        <DataTemplate>
                                            <ViewCell>
                                                <StackLayout>
                                                    <StackLayout>
                                                        <BoxView Color="{Binding Code}" HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="8" HeightRequest="8" />
                                                    </StackLayout>
                                                    <BoxView Color="Transparent" HorizontalOptions="Center" VerticalOptions="Center" HeightRequest="2"/>
                                                </StackLayout>
                                            </ViewCell>
                                        </DataTemplate>
                                    </controls:ColorCodeRepeater.ItemTemplate>
                                </controls:ColorCodeRepeater>
                            </Grid>
                        </DataTemplate>
                    </c1:C1Calendar.DaySlotTemplate>
                </c1:C1Calendar>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    
    

    Codebehind

        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class PlanboardPage : ContentPage
        {
            PlanboardViewModel viewModel;
            
            public PlanboardPage()
            {
                
                InitializeComponent();
                BindingContext = viewModel = new PlanboardViewModel(this);
                BindEvents();
                
                switch (Device.RuntimePlatform)     
                {
                    case Device.iOS:
                        calendar.FontFamily = "OpenSans-Regular";
                        calendar.HeaderFontFamily = "OpenSans-Bold";
                        break;
                    case Device.Android:
                        calendar.FontFamily = "OpenSans-Regular.ttf#OpenSans-Regular";
                        calendar.HeaderFontFamily = "OpenSans-Bold.ttf#OpenSans-Bold";
                        break;
                        
                }
                
                calendar.ViewModeAnimation.AnimationMode = CalendarViewModeAnimationMode.ZoomOutIn;
                calendar.ViewModeAnimation.ScaleFactor = 1.1;
                calendar.ViewModeAnimation.Duration = TimeSpan.FromMilliseconds(150);                
                calendar.NavigateAnimation.Duration = TimeSpan.FromMilliseconds(150);
                calendar.MinDate = DateTime.Now.AddMonths(-6);
                calendar.MaxDate = DateTime.Now.AddMonths(6);
                
            }        
    
            /// <summary>
            /// Handle dayslotloading event
            /// </summary>        
            public void OnDaySlotLoading(object sender, CalendarDaySlotLoadingEventArgs e)
            {
                if(e.Date >= calendar.ActualMinDate && e.Date <= calendar.ActualMaxDate)
                {
                    if (viewModel.PlanboardItems != null && viewModel.PlanboardItems.Count > 0)
                        UpdateDaySlot(e.DaySlot, e.Date);
                }            
            }
    
            /// <summary>
            /// Update dayslot binding context
            /// </summary>        
            private void UpdateDaySlot(View daySlot, DateTime date)
            {                      
                var colorCodes = viewModel.GetColorCodesForDay(date);
                
                if (colorCodes != null && colorCodes.Count > 0)
                {                
                    var margin = new Thickness(20, -20, 0, 0);                
                    var height = 8;
    
                    switch (colorCodes.Count)
                    {                    
                        case 2:
                            height = 24;
                            margin = new Thickness(5, -20, 0, 0);
                            break;
                        case 3:
                            height = 40;
                            margin = new Thickness(-11, -20, 0, 0);
                            break;
                    }
                            
                    daySlot.BindingContext = new
                    {
                        date.Day,
                        ColorCodes = colorCodes,
                        Height = height,
                        Margin = margin
                    };
                }
                else
                {
                    daySlot.BindingContext = new
                    {
                        date.Day
                    };
                }                                     
            }
    }
    
    
  • Posted 28 September 2017, 12:50 am EST

    Hello

    I can give a few possible suggestions. First, Xamarin has a general guide for optimizing layout performance that might be helpful here: https://developer.xamarin.com/guides/xamarin-forms/deployment-testing/performance/. Generally, it helps to try to cut down on nested layouts (especially when they contain only a single element), and limiting setting verticaloptions and horizontaloptions where possible. Also it might be worth checking whether it behaves differently with some kind of local dummy data just to eliminate some kind of performance issue with the database or webservice.

    I’ll also add that Android performance for Xamarin.Forms is something that Xamarin is working on right now too. I believe in their next major release (https://forums.xamarin.com/discussion/85747/xamarin-forms-feature-roadmap/p1) they’ll start rolling out some new features like fast renderers for Android which we’ll be evaluating that might help also help performance.

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels