Overview

This document provides an overview of the ShinobiCalendars control. It describes the features of the control and its associated concepts.

ShinobiCalendars displays days, weeks and months in an infinite scroll view, and allows interaction with these dates. The user can zoom in and out using pinch gestures to show / hide details of particular dates.

To quickly get up and running, follow the Quick Start Guide. Alternatively, for a more detailed description of the calendar’s features, keep reading.

ShinobiCalendar

A ShinobiCalendar is a container for a SCalendarMonthScrollView. To add a calendar to your project, instantiate this class and add it to your view, either through interface builder or programatically. The ShinobiCalendar class fully supports auto-layout and autoresizing masks.

    ShinobiCalendar *calendar = [[ShinobiCalendar alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:calendar];

Infinite Scrolling

In it’s default state, the calendar will scroll forever. There is no limit to the date that the user can scroll to initially.

Minimum/ Maximum Dates

The calendar can be restricted to only displaying certain dates through it’s minimumDate and maximumDate properties. The calendar will then limit the scrolling so that the user can not pass the minimum or maximum dates. Other dates may be visible at some zoom levels in order to keep the calendar’s layout and give the user context of where they are, but the user won’t be able to interact with dates out of this range, and they will be styled differently.

Zoom Levels

The calendar is capable of displaying dates at four different zoom levels, which are illustrated below.

SCalendarZoomLevelYear

The year zoom level.

SCalendarZoomLevelMonth

The month zoom level.

SCalendarZoomLevelWeek

The week zoom level.

SCalendarZoomLevelDay

The day zoom level.

Transitioning Between Zoom Levels

In order to change the zoom level that the calendar is currently displaying, there are two options. The first is through user gestures, (pinches and double taps) and the second is programmatic zooming.

User Interaction Transitions

The calendar comes with a powerful set of user interaction gestures that can be used to navigate between the different zoom levels.

The first of these is the double tap. If a user double taps a date, then the calendar will zoom in to the next zoom level (if it is not already at the maximum zoom level), and center on that date.

The second is a pinch gesture. If a user pinches outwards then the calendar will zoom in, keeping the date below the pinch at the center. If the user pinches inwards the calendar will zoom out, again, keeping the date below the pinch at the center.

This pinch gesture recognizer is exposed on the ShinobiCalendar view, as gestureRecognizer. You can use this property when you want the calendar to simultaneously recognize other gestures in your application, and disable it if you want to turn off gestures on your calendar.

Programmatic Transitions

The calendar also has a set of zoom methods that allow your application to manually zoom in, out, or to a certain date at a certain zoom level.

These methods are on ShinobiCalendar:

- (void)zoomIn;

This zooms to the next zoom level around the center date.

- (void)zoomOut;

This zooms out to the previous zoom level around the center date.

- (void)scrollToDate:(NSDate *)date atZoomLevel:(SCalendarZoomLevel)zoomLevel animated:(BOOL)animated;

This allows you to specify the date you wish to be at the center of the calendar, as well as the zoom level. This means that you can specify any date and any zoom level and the calendar will update to show it. There’s also the option to animate this change, or for it to happen instantly.

Minimum/Maximum Zoom Levels

It is often not appropriate to allow the user to zoom to every level of the calendar. When using the calendar as a date picker, for example, it makes sense to restrict the calendar so that it only shows dates at the year view.

You can easily customise the minimum and maximum zoom level so that the user can only see certain levels on the calendar. The maximum zoom level is the deepest level that a user can get to in the calendar. If this is set to month, for example, then the user will not be able to pinch or tap to get to the week or day zoom levels. The minimum zoom level is the highest level that a user can get to in the calendar. If this is set to month view, for example, then the user will not be able to get to the year view. The month view is as far as they can zoom out.

These two properties (minimumZoomLevel and maximumZoomLevel) are on the ShinobiCalendar view, and default to SCalendarZoomLevelYear and SCalendarZoomLevelDay, respectively. This means that by default, the user is not restricted in which zoom levels they can transition to.

Month Columns At Year Zoom Level

It is possible for the user to customise the number of month columns that are displayed on the calendar when it is at the year zoom level, through the use of the calendar’s monthColumnsAtYearZoomLevel property. This defaults to 3 on iPad, and 2 on iPhone. The minimum value for this property is of course 1, and the maximum value is 4.

Styling The Calendar

In order to change the appearance of the calendar, you can modify properties on the SCalendarStyle style property on the calendar, or provide your own custom subclass. There are three default styles provided by the calendar as a default. The first, SCalendarStyle, is the base class, and should be subclassed when creating a custom style. It provides a very basic default style. You can also use a light style, SCalendarLightStyle and a dark style, SCalendarDarkStyle to change the default appearance of the calendar.

Inactive/Active Styles

Nearly every component of the style has an inactive and an active style. Inactive styles apply to dates that are displayed that are outside of the minimum/maximum date range. If a date is before the minimum date, then it will have the inactive style. If a date is after the maximum date, then it will have the inactive style. In all other cases, including where the minimum/maximum dates are not set, then the calendar will use the active style.

Default/Highlighted Styles

Throughout the style properties, you will also find the word ‘highlighted’. This means that this style is only applied when there is an event on this date. The SCalendarDayStyle’s highlightedDayLabelColor, for example, will only apply to the day label if there is at least 1 event on the day that the label represents. Where there are no events, it will simply use the dayLabelColor property.

Where the Style Properties Apply

Year View Styles

The year zoom level. This shows where the different style properties apply when the calendar is at the year zoom level. Notice that there are a lot of other styles visible. The image illustrates one of the places where the month style will apply, as well as the day style, illustrating the difference between normal and highlighted days.

Month View Styles

The month zoom level. This shows where the different style properties apply when calendar is at the month zoom level. This level is the only level where the indicator styles apply. Indicators are not visible in any other view.

Week View Styles

The week zoom level. This shows where the different style properties apply when the calendar is at the week zoom level.

Day View Styles

The day zoom level. This shows where the different style properties apply when the calendar is at the day zoom level.

SCalendarDataSource

The above gives an overview of how you can customise the calendar’s appearance, but it is also important to know how to display events on the calendar. To add events to the calendar, set a class that conforms to the SCalendarDataSource protocol to the calendar’s dataSource property.

This protocol contains two required methods. The first allows you to specify an array of events for a given date. - (NSArray )shinobiCalendar:(ShinobiCalendar )calendar eventsForDate:(NSDate *)date; This array must be filled with SCalendarEvent model objects. These model objects allow you to specify a name, image, start time and end time. Performance is crucial here. Try to keep this code as fast as possible, as the scroll view can slow down and be displayed at a lower frame rate if the dataSource’s implementation of method is expensive. If there are no events for this date, simply return nil.

The second method in the protocol allows you to specify an event view for the event. Event views are visible at the week and day zoom levels.

Event Views

To provide the calendar with an event view, you must implement the following method.

- (SCalendarEventView *)shinobiCalendar:(ShinobiCalendar *)calendar eventViewForEvent:(SCalendarEvent *)event;

Due to the performance issues around allocating and setting up new views, this is, unfortunately, not a simple case of building a new view and returning it. The calendar has a caching and reuse system, similar to that of UITableView, which allows you to provide it with event views, while maintaining a reponsive scrolling experience.

Caching and Reuse

In order to allow the calendar to display an event view, you must first register the Class of the event view that you wish to display. To use the default event view provided with the calendar, add the following line to your code before it appears in the view.

    [self.calendar registerEventViewClass:[SCalendarEventView class] forEventReuseIdentifier:@"eventView"];

This tells the calendar that when you come to dequeue an event view with the “eventView” identifier, that it should provide you with an instance of SCalendarEventView.

Then, all that’s left to do is in eventViewForEvent:. Ask the calendar to dequeue a reusable event view with that identifier.

    return [calendar dequeueReusableEventViewWithIdentifier:@"eventView"];

This will then use the event view to display the event that is passed into eventViewForEvent:

Custom Event Views

If you wish to display a subclass of SCalendarEventView on the calendar, all you have to do is change the class you pass in to the registerEventViewClass:forEventReuseIdentifier: method mentioned above. It is possible to register multiple different classes. Then, in the eventViewForEvent method, you can decide which type of view you want to return for any given event. All you need to do is ensure that they are registered with different eventReuseIdentifier parameter.

SCalendarDelegate

The ShinobiCalendar also has a delegate property. Use a class that conforms the SCalendarDelegate protocol as the delegate property to respond to events that occur during interaction with the calendar.

Interaction Events

It may be appropriate for your application to externally respond to events that take place on the calendar. The calendar provides three methods to indicate when something has been tapped.

- (void)shinobiCalendar:(ShinobiCalendar *)calendar selectedEvent:(SCalendarEvent *)event;

This method tells you when an event has been selected. This event can only occur at the week or day zoom levels, as that is the only time events are visible on the calendar.

- (void)shinobiCalendar:(ShinobiCalendar *)calendar tappedDate:(NSDate *)date;

This method will tell you when a date has been tapped. This can happen at any zoom level and only occurs if it is a single tap.

- (void)shinobiCalendar:(ShinobiCalendar *)calendar doubleTappedDate:(NSDate *)date;

This method will tell you when a date has been double tapped. This can happen at any zoom level and only occurs if it is a double tap. The double tap will also cause the calendar to zoom in, if it is not already at it’s maximum zoom level.

View Customization

There are also methods on SCalendarDelegate that manually allow you to modify the views that are about to be displayed on the screen. willDisplayYearTitleLabel: and willDisplayMonthTitleLabel: provide you with a way to modify the year and month title labels before they come into view. This allows you to set their text alignment, change their colors and fonts, and add subviews.

willDisplayDayNumberLabelForToday: is similar, but it is only called with the day label that represents the current day.

Finally, eventIndicatorImageForDate: allows you to specify a custom event indicator image for every date with an event on it. This allows the user to have different indicator images for each event indicator shown at the month zoom level.