PMCalendar

Yet another calendar component for iOS. Compatible with iOS 4.0 (iPhone & iPad) and higher. Supports presenting as a popover and very flexible UI tuning. Default theme is inspired by https://github.com/ocrickard/OCCalendar

378
88
Objective-C

PMCalendar v0.3.2

platform
version

Yet another calendar component for iOS. Compatible with iOS 4.0 (iPhone & iPad) and higher.

UI is inspired by ocrickard’s OCCalendarController. It’s quite good component, but doesn’t have some useful features which I wanted to see. Unfortunately OCCalendarController very hard to maintain, so I decided to create my own implementation.

PMCalendar supports selection of multiple dates within one or several months, appears as a popover (if you used UIPopoverController before, you’ll find PMCalendar management very similar), supports orientation changes out of the box and does not require any third party frameworks.

PMCalendar uses iOS’ CoreGraphics and CoreText frameworks.

It’s definitely not bug-free, so if you’re going to use PMCalendar in production, please test it hard 😉

Feel free to concact me in case of any questions or suggestions. If you feel you know how to improve PMCalendar don’t hesitate to contact me or send a pull request.

Legal

PMCalendar is released under the MIT License.

Screenshots

Screenshot 1  Screenshot 2

Screenshot 3

Usage

  • Add PMCalendar directory to your Xcode project
  • Add CoreGraphics and CoreText frameworks to your project
  • #import “PMCalendar.h”
  • Create instance of PMCalendarController with specific theme name (see below) and size:
        PMCalendarController *calendarController = [[PMCalendarController alloc] initWithThemeName:@"my super theme name" andSize:CGSizeMake(300, 200)];
  • Or use defaults:
        // default theme name (default.plist) and size (see default.plist for details)
        PMCalendarController *calendarController = [[PMCalendarController alloc] init];
        // default theme name (default.plist) and specific size
        PMCalendarController *calendarController = [[PMCalendarController alloc] initWithSize:CGSizeMake(300, 200)];
        // specific theme name and default calendar size for this theme
        PMCalendarController *calendarController = [[PMCalendarController alloc] initWithThemeName:@"my super theme name"];
  • Implement PMCalendarControllerDelegate methods to be aware of controller’s state change:
        - (BOOL)calendarControllerShouldDismissCalendar:(PMCalendarController *)calendarController;
        - (void)calendarControllerDidDismissCalendar:(PMCalendarController *)calendarController;
        - (void)calendarController:(PMCalendarController *)calendarController didChangePeriod:(PMPeriod *)newPeriod;
  • Don’t forget to assign delegate!
        calendarController.delegate = self;
  • Present calendarController from a view (i.e. UIButton), so calendar could position itself during rotation:
         [calendarController presentCalendarFromView:pressedButton
                            permittedArrowDirections:PMCalendarArrowDirectionUp | PMCalendarArrowDirectionLeft
                                           isPopover:YES
                                            animated:YES];
  • Or CGRect:
         [calendarController presentCalendarFromRect:CGRectMake(100, 100, 10, 10)
                                              inView:self.view
                            permittedArrowDirections:PMCalendarArrowDirectionUp | PMCalendarArrowDirectionLeft
                                           isPopover:YES
                                            animated:YES];
  • Dismiss it:
         [calendarController dismissAnimated:YES];

PMPeriod

    @interface PMPeriod : NSObject

    @property (nonatomic, strong) NSDate *startDate;
    @property (nonatomic, strong) NSDate *endDate;

    /**
     * Creates new period with same startDate and endDate
     */
    + (id) oneDayPeriodWithDate:(NSDate *) date;

    + (id) periodWithStartDate:(NSDate *) startDate endDate:(NSDate *) endDate;

    - (NSInteger) lengthInDays;

    /**
     * Creates new period from self with proper order of startDate and endDate.
     */
    - (PMPeriod *) normalizedPeriod;

    @end

Implemented properties

    @property (nonatomic, assign) id<PMCalendarControllerDelegate> delegate;

Selected period

    @property (nonatomic, strong) PMPeriod *period;

Period allowed for selection

    @property (nonatomic, strong) PMPeriod *allowedPeriod;

Monday is a first day of week. If set to NO then Sunday is a first day

    @property (nonatomic, assign, getter = isMondayFirstDayOfWeek) BOOL mondayFirstDayOfWeek;

If NO, only one date can be selected. Otherwise, user can pan to select period

    @property (nonatomic, assign) BOOL allowsPeriodSelection;

If YES, user can long press on arrow to fast iterate through months

    @property (nonatomic, assign) BOOL allowsLongPressMonthChange;

Direction of the arrow (similar to UIPopoverController’s arrowDirection)

    @property (nonatomic, readonly) PMCalendarArrowDirection arrowDirection;

Size of a calendar controller

    @property (nonatomic, assign) CGSize size;

Returns whether the popover is visible (presented) or not

    @property (nonatomic, assign, readonly, getter = isCalendarVisible) BOOL calendarVisible;

Themes (beta!)

Themes allows you to create your own calendar component look without touching PMCalendar code. In theory… On practice current implementation is a compromise between flexibility and speed of drawing of the component. Therefore, some theme properties which you expect to be working does not work 😃.

However, current implementation is powerful enough to create for example something like this:

Apple calendar theme 1 Apple calendar theme 2

Themes documentation is in progress, so for now please use two examples (“default.plist” and “apple calendar.plist”) as a refernce.

If you wish to share theme you created for PMCalendar, please contact me, I’ll add it together with a link to your project 😃.