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:
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
Xuni Calendar with no navigation buttons Later in this topic I will show how to customize the buttons.
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"
Xuni Calendar set with a custom header month format string.
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";
}
}
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.
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 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.
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. To summarize the different ways to customize the calendar header, we’ve seen four basic scenarios:
You can browse and download this entire sample for Xamarin.Forms on GitHub here.