In this topic we will explore the different ways that we can customize the header of Xuni Calendar. As of the 2016 v2 update, Xuni Calendar supports three different view modes (month, year, and decade), and as such there are three different places you may want to customize the header content. By default, the calendar displays general month/year formats that should satisfy most users. Examples:

  • Month View --> July 2016
  • Year View --> 2016
  • Decade View --> 2010 – 2019

In addition to this text the header also shows two navigation buttons. The buttons are not necessary since the calendar supports swiping gestures to navigate, so you can easily remove them by just writing one line of code.


calendar.ShowNavigationButtons = False  

Calendar_Header_No_Buttons_edited Xuni Calendar with no navigation buttons Later in this topic I will show how to customize the buttons.

Customizing the Header Month Format

Let’s say we want to have a different format for the month view header. In Xuni Calendar it’s very easy to adjust the format by setting the HeaderMonthFormat property. This property accepts a string that can contain any order of common date & time format specifiers. For example, the format string below will display the date like “07: Jul 16”.


HeaderMonthFormat="MM: MMM yy"  

Calendar_Header_Format_String_edited Xuni Calendar set with a custom header month format string.

Customizing the Month, Year or Decade Format Programmatically

Since year and decade formats are less likely to be customized, we didn’t add any special format properties for them. But it’s still quite easy to change. Xuni Calendar also supports a HeaderLoading event that can be used to programmatically change the header text for any view. For example, this code overrides the header text for each view in different ways.


private void Calendar_HeaderLoading(object sender, Xuni.Forms.Calendar.CalendarHeaderLoadingEventArgs e)  
{  
    if(e.ViewMode == Xuni.Forms.Calendar.CalendarViewMode.Month)  
    {  
        e.Header = e.Date.Month.ToString() + " " + e.Header;  
    }  
    else if(e.ViewMode == Xuni.Forms.Calendar.CalendarViewMode.Year)  
    {  
        e.Header = e.Header + "!";  
    }  
    else if(e.ViewMode == Xuni.Forms.Calendar.CalendarViewMode.Decade)  
    {  
        e.Header = "Select a year";  
    }  
}  

Calendar_Header_Loading_Event_edited Xuni Calendar with year and decade header text customized programmatically So if you do need to change month and year or decade view, you could use the HeaderLoading event rather than HeaderMonthFormat, since the event will also take care of the month format. Simply set the e.Header property within this event to any text you want. You can obtain the displayed date using e.Date.

Creating a Complete Custom Header

If the approaches above are not enough to meet your requirements, Xuni Calendar does have one final solution: create a completely new header from scratch. It’s easier than it sounds. First, you can hide the entire default header by setting ShowHeader = False. Then, on your calendar page, you can construct your own header using basic elements like a Label, Buttons, or Images. Now you are only limited by what the platform offers. For example, I will create a custom header that looks and behaves like this: Xuni-Calendar-Custom-Header-Buttons Xuni Calendar has the necessary hooks (events) to listen to user interaction and update your custom header. There is one key event you’ll want to subscribe to: DisplayDateChanged. There’s also DisplayDateChanging and ViewModeChanged, but DisplayDateChanged is enough for my complete sample.

  • DisplayDateChanged – fires when the displayed date (month) is changed by the user by swiping left and right.
  • ViewModeChanged – fires when the user changes the view mode by tapping the header. But in this sample the entire header is customized so we don’t need this event.

In the DisplayDateChanged event we will update the label text in the header.


async private void Calendar_DisplayDateChanged(object sender, EventArgs e)  
{  
    await UpdateHeaderText();  
}  

The UpdateHeaderText method not only formats all three view modes, but it also applies a little animation to the label.


async private Task UpdateHeaderText()  
{  
    // animate label  
    lblMonthYear.TranslationY = 20;  
    await lblMonthYear.TranslateTo(0, 0, 100, Easing.CubicOut);  

    if (calendar.ViewMode == Xuni.Forms.Calendar.CalendarViewMode.Month)  
    {  
        lblMonthYear.Text = DateTimeFormatInfo.CurrentInfo.GetMonthName(calendar.DisplayDate.Month) + " " + calendar.DisplayDate.Year.ToString();  
    }  
    else if(calendar.ViewMode == Xuni.Forms.Calendar.CalendarViewMode.Year)  
    {  
        lblMonthYear.Text = calendar.DisplayDate.Year.ToString();  
    }  
    else  
    {  
        lblMonthYear.Text = calendar.DisplayDate.Year.ToString().Substring(0, 3) + "0 - " + calendar.DisplayDate.Year.ToString().Substring(0, 3) + "9";  
    }  
}  

This code above doesn’t really change the header formats – it recreates the default formats but now we have complete control over the header appearance. Observe that we can get the full or abbreviated month names from the System.Globalization.DateTimeFormatInfo object. Next, we need to wire up our custom buttons to navigate the calendar. You can call the asynchronous GoBackAsync and GoForwardAsync to navigate the calendar with animation, just like the default buttons do.


async private void TgrPrevMonth_Tapped(object sender, EventArgs e)  
{  
    await calendar.GoBackAsync();  
}  

async private void TgrNextMonth_Tapped(object sender, EventArgs e)  
{  
    await calendar.GoForwardAsync();  
}  

You can download the full sample below to see the entire implementation. You’ll notice I’m technically using images with TapGestureRecognizers rather than buttons. Lastly, we want the user to be able to toggle the view modes by tapping the header label.


async private void TgrMonthYear_Tapped(object sender, EventArgs e)  
{  
    if(calendar.ViewMode == Xuni.Forms.Calendar.CalendarViewMode.Month)  
    {  
        await calendar.ChangeViewModeAsync(Xuni.Forms.Calendar.CalendarViewMode.Year);  
    }  
    else if(calendar.ViewMode == Xuni.Forms.Calendar.CalendarViewMode.Year)  
    {  
        await calendar.ChangeViewModeAsync(Xuni.Forms.Calendar.CalendarViewMode.Decade);  
    }  
    else  
    {  
        await calendar.ChangeViewModeAsync(Xuni.Forms.Calendar.CalendarViewMode.Month);  
    }  
    // added: update header text here when we change  
    await UpdateHeaderText();  
}  

This code basically recreates the default header tapping behavior. The navigation cycle works like this:

Month --> Year --> Decade --> Month

Earlier I stated that I didn’t need to use the ViewModeChanged event and it’s because I can update the header text when the view mode changes from my tapped event above. Calendar_Header_Custom_Buttons_edited To summarize the different ways to customize the calendar header, we’ve seen four basic scenarios:

  1. Hide the buttons only by setting ShowNavigationButtons = False
  2. Format just the month header text by setting HeaderMonthFormat.
  3. Format month, year and decade header text within the HeaderLoading event.
  4. Create a completely custom header, with optional buttons, by setting ShowHeader = False and reconstructing the header parts however you want in XAML/C#.

You can browse and download this entire sample for Xamarin.Forms on GitHub here.