Calendar: Customizations

TKCalendar allows customizing almost evety aspect of its visual appearance. This article demonstrates some of the customization techniques that can be used with it.

TKCalendar comes with two predefined themes:

You can switch between themes by usig the theme property:

TKCalendar *calendarView = [[TKCalendar alloc] initWithFrame:self.view.bounds];
calendarView.theme = [TKCalendarIPadTheme new];
[self.view addSubview:calendarView];
let calendar = TKCalendar(frame: self.view.bounds)
calendar.theme = TKCalendarIPadTheme()
calendar.delegate = self
TKCalendar calendar = new TKCalendar (this.View.Bounds);
calendar.Theme = new TKCalendarIPadTheme ();
calendar.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
this.View.AddSubview (calendar);

TKCalendar uses presenter classes to render different view modes. They all inherit from UIView and contain subviews with settings that can be changed. Most useful settings are grouped in a style property in the presenter class:

TKCalendarMonthPresenter *presenter = (TKCalendarMonthPresenter*)calendarView.presenter;
presenter.style.titleCellHeight = 40;
presenter.style.backgroundColor = [UIColor redColor];
presenter.headerIsSticky = YES;
presenter.style.monthNameTextEffect = TKCalendarTextEffectLowercase;
[presenter update:NO];
let presenter = calendar.presenter as! TKCalendarMonthPresenter
presenter.style.titleCellHeight = 40
presenter.style.backgroundColor = UIColor.red
presenter.headerIsSticky = true
presenter.style.monthNameTextEffect = TKCalendarTextEffect.lowercase
presenter.update(false)
TKCalendarMonthPresenter presenter = (TKCalendarMonthPresenter)calendar.Presenter;
presenter.Style.TitleCellHeight = 40;
presenter.Style.BackgroundColor = UIColor.Yellow;
presenter.HeaderIsSticky = true;
presenter.Style.MonthNameTextEffect = TKCalendarTextEffect.Lowercase;
presenter.Update (false);

There are cases when specific cells must have custom design based on the cell state (e.g. today, weekend, selected). This can be dobe by adopging the TKCalendarDelegate protocol and implementing its calendar:upateVisualsForCell: method:

- (void)calendar:(TKCalendar*)calendar updateVisualsForCell:(TKCalendarCell*)cell;
{
    if ([cell isKindOfClass:[TKCalendarDayCell class]]) {
        TKCalendarDayCell *dayCell = (TKCalendarDayCell*)cell;
        if (dayCell.state & TKCalendarDayStateToday) {
            cell.style.textColor = [UIColor colorWithRed:0.0039 green:0.5843 blue:0.5529 alpha:1.0000];
        }
        else {
            cell.style.textColor = [UIColor greenColor];
        }
    }
}
func calendar(_ calendar: TKCalendar, updateVisualsFor cell: TKCalendarCell) {
    if cell.isKind(of: TKCalendarDayCell.self) {
        let dayCell: TKCalendarDayCell = cell as! TKCalendarDayCell
        if (dayCell.state.rawValue & TKCalendarDayState.today.rawValue) != 0 {
            cell.style().textColor = UIColor(red: 0.0039, green: 0.5843, blue: 0.5529, alpha: 1.0000)
        }
        else {
            cell.style().textColor = UIColor.black
        }
    }
}
public override void UpdateVisualsForCell (TKCalendar calendar, TKCalendarCell cell)
{
    if (cell is TKCalendarDayCell) {
        TKCalendarDayCell dayCell = (TKCalendarDayCell)cell;
        if ((dayCell.State & TKCalendarDayState.Today) != 0) {
            cell.Style.TextColor = UIColor.Red;
        }
        else {
            cell.Style.TextColor = UIColor.Purple;
        }
    }
}

The cell can be replaced with a custom one for more complex scenarios. This can be done by implementing the calendar:viewForCellOfKind: method of TKCalendarDelegate protocol:

- (TKCalendarCell *)calendar:(TKCalendar *)calendar viewForCellOfKind:(TKCalendarCellType)cellType
{
    if (cellType == TKCalendarCellTypeDay) {
        DocsCustomCell *cell = [DocsCustomCell new];
        return cell;
    }
    return nil;
}
func calendar(_ calendar: TKCalendar, viewForCellOfKind cellType: TKCalendarCellType) -> TKCalendarCell? {
    if cellType == TKCalendarCellType.day {
        let cell = DocsCustomCell()
        return cell
    }
    return nil
}
public override TKCalendarCell ViewForCellOfKind (TKCalendar calendar, TKCalendarCellType cellType)
{
    if (cellType == TKCalendarCellType.Day) {
        DocsCustomCell cell = new DocsCustomCell ();
        return cell;
    }
    return null;
}

The following is the implementation of the CustomCell class:

@implementation DocsCustomCell

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
    }
    return self;
}

- (void)updateVisuals
{
    [super updateVisuals];

    if (self.state & TKCalendarDayStateToday) {
        self.label.textColor = [UIColor redColor];
    }
    else {
        self.label.textColor = [UIColor blueColor];
    }
}

@end
class DocsCustomCell: TKCalendarDayCell {
    override func updateVisuals() {
        super.updateVisuals()

        if self.state.rawValue & TKCalendarDayState.today.rawValue != 0 {
            self.label.textColor = UIColor.red
        }
        else {
            self.label.textColor = UIColor.blue
        }
    }
}
public class DocsCustomCell : TKCalendarDayCell
{
    public DocsCustomCell ()
    {
    }

    public override void UpdateVisuals ()
    {
        base.UpdateVisuals ();

        if ((this.State & TKCalendarDayState.Today) != 0) {
            this.Label.TextColor = UIColor.Green;
        } else {
            this.Label.TextColor = UIColor.Blue;
        }
    }
}

The result is presented below: