From 4a6e6e2377ad23a790bda441636cc6dfcc7778a1 Mon Sep 17 00:00:00 2001 From: Nguyen Truong Luu Date: Fri, 16 Sep 2022 17:59:26 +0700 Subject: [PATCH] Add month year and year only picker --- .gitignore | 3 + .../project.pbxproj | 32 +- .../Pickers/AbstractActionSheetPicker.m | 1 - .../Pickers/ActionSheetDatePicker.m | 175 +++++-- .../Pickers/CoreActionSheetMonthYearPicker.m | 477 ++++++++++++++++++ .../Pickers/include/ActionSheetDatePicker.h | 31 +- .../include/CoreActionSheetMonthYearPicker.h | 51 ++ .../Swift-Example/Base.lproj/Main.storyboard | 90 +++- .../SWTableViewController.swift | 154 +++--- 9 files changed, 857 insertions(+), 157 deletions(-) create mode 100644 CoreActionSheetPicker/CoreActionSheetPicker/Pickers/CoreActionSheetMonthYearPicker.m create mode 100644 CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/CoreActionSheetMonthYearPicker.h diff --git a/.gitignore b/.gitignore index 94ef148c8..6a3d28279 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ Example Projects/Carthage-example/Carthage/Checkouts +### OS generated files ### +.DS_Store +.DS_Store? ### Xcode ### build/ diff --git a/CoreActionSheetPicker/CoreActionSheetPicker.xcodeproj/project.pbxproj b/CoreActionSheetPicker/CoreActionSheetPicker.xcodeproj/project.pbxproj index 49c0ccdd9..4a7aa54b7 100644 --- a/CoreActionSheetPicker/CoreActionSheetPicker.xcodeproj/project.pbxproj +++ b/CoreActionSheetPicker/CoreActionSheetPicker.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ 6BA0DC7927B228D5009EC711 /* DistancePickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA0DC6527B228D5009EC711 /* DistancePickerView.m */; }; 6BA0DC7A27B228D5009EC711 /* ActionSheetMultipleStringPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA0DC6627B228D5009EC711 /* ActionSheetMultipleStringPicker.m */; }; 6BA0DC7B27B228D5009EC711 /* AbstractActionSheetPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA0DC6727B228D5009EC711 /* AbstractActionSheetPicker.m */; }; + F8E2BD9728D48A3400970139 /* CoreActionSheetMonthYearPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E2BD9528D48A3400970139 /* CoreActionSheetMonthYearPicker.m */; }; + F8E2BD9828D48A3400970139 /* CoreActionSheetMonthYearPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = F8E2BD9628D48A3400970139 /* CoreActionSheetMonthYearPicker.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -67,6 +69,8 @@ 6BA0DC6527B228D5009EC711 /* DistancePickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DistancePickerView.m; sourceTree = ""; }; 6BA0DC6627B228D5009EC711 /* ActionSheetMultipleStringPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ActionSheetMultipleStringPicker.m; sourceTree = ""; }; 6BA0DC6727B228D5009EC711 /* AbstractActionSheetPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AbstractActionSheetPicker.m; sourceTree = ""; }; + F8E2BD9528D48A3400970139 /* CoreActionSheetMonthYearPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreActionSheetMonthYearPicker.m; sourceTree = ""; }; + F8E2BD9628D48A3400970139 /* CoreActionSheetMonthYearPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreActionSheetMonthYearPicker.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -144,15 +148,16 @@ isa = PBXGroup; children = ( 6BA0DC5527B228D5009EC711 /* include */, + 6BA0DC6727B228D5009EC711 /* AbstractActionSheetPicker.m */, + 6BA0DC6227B228D5009EC711 /* ActionSheetCustomPicker.m */, 6BA0DC5327B228D5009EC711 /* ActionSheetDatePicker.m */, - 6BA0DC5427B228D5009EC711 /* ActionSheetLocalePicker.m */, 6BA0DC6127B228D5009EC711 /* ActionSheetDistancePicker.m */, - 6BA0DC6227B228D5009EC711 /* ActionSheetCustomPicker.m */, - 6BA0DC6327B228D5009EC711 /* SWActionSheet.m */, + 6BA0DC5427B228D5009EC711 /* ActionSheetLocalePicker.m */, + 6BA0DC6627B228D5009EC711 /* ActionSheetMultipleStringPicker.m */, 6BA0DC6427B228D5009EC711 /* ActionSheetStringPicker.m */, + F8E2BD9528D48A3400970139 /* CoreActionSheetMonthYearPicker.m */, 6BA0DC6527B228D5009EC711 /* DistancePickerView.m */, - 6BA0DC6627B228D5009EC711 /* ActionSheetMultipleStringPicker.m */, - 6BA0DC6727B228D5009EC711 /* AbstractActionSheetPicker.m */, + 6BA0DC6327B228D5009EC711 /* SWActionSheet.m */, ); path = Pickers; sourceTree = ""; @@ -160,17 +165,18 @@ 6BA0DC5527B228D5009EC711 /* include */ = { isa = PBXGroup; children = ( - 6BA0DC5927B228D5009EC711 /* CoreActionSheetPicker.h */, - 6BA0DC5627B228D5009EC711 /* ActionSheetCustomPicker.h */, - 6BA0DC5727B228D5009EC711 /* ActionSheetStringPicker.h */, - 6BA0DC5827B228D5009EC711 /* SWActionSheet.h */, 6BA0DC5A27B228D5009EC711 /* AbstractActionSheetPicker.h */, - 6BA0DC5B27B228D5009EC711 /* ActionSheetMultipleStringPicker.h */, - 6BA0DC5C27B228D5009EC711 /* DistancePickerView.h */, + 6BA0DC5627B228D5009EC711 /* ActionSheetCustomPicker.h */, 6BA0DC5D27B228D5009EC711 /* ActionSheetCustomPickerDelegate.h */, 6BA0DC5E27B228D5009EC711 /* ActionSheetDatePicker.h */, - 6BA0DC5F27B228D5009EC711 /* ActionSheetLocalePicker.h */, 6BA0DC6027B228D5009EC711 /* ActionSheetDistancePicker.h */, + 6BA0DC5F27B228D5009EC711 /* ActionSheetLocalePicker.h */, + 6BA0DC5B27B228D5009EC711 /* ActionSheetMultipleStringPicker.h */, + 6BA0DC5727B228D5009EC711 /* ActionSheetStringPicker.h */, + F8E2BD9628D48A3400970139 /* CoreActionSheetMonthYearPicker.h */, + 6BA0DC5927B228D5009EC711 /* CoreActionSheetPicker.h */, + 6BA0DC5C27B228D5009EC711 /* DistancePickerView.h */, + 6BA0DC5827B228D5009EC711 /* SWActionSheet.h */, ); path = include; sourceTree = ""; @@ -192,6 +198,7 @@ 6BA0DC7327B228D5009EC711 /* ActionSheetLocalePicker.h in Headers */, 6BA0DC6C27B228D5009EC711 /* SWActionSheet.h in Headers */, 6BA0DC7127B228D5009EC711 /* ActionSheetCustomPickerDelegate.h in Headers */, + F8E2BD9828D48A3400970139 /* CoreActionSheetMonthYearPicker.h in Headers */, 6BA0DC6D27B228D5009EC711 /* CoreActionSheetPicker.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -302,6 +309,7 @@ 6BA0DC7527B228D5009EC711 /* ActionSheetDistancePicker.m in Sources */, 6BA0DC7A27B228D5009EC711 /* ActionSheetMultipleStringPicker.m in Sources */, 6BA0DC6827B228D5009EC711 /* ActionSheetDatePicker.m in Sources */, + F8E2BD9728D48A3400970139 /* CoreActionSheetMonthYearPicker.m in Sources */, 6BA0DC6927B228D5009EC711 /* ActionSheetLocalePicker.m in Sources */, 6BA0DC7927B228D5009EC711 /* DistancePickerView.m in Sources */, ); diff --git a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/AbstractActionSheetPicker.m b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/AbstractActionSheetPicker.m index 05e741823..3e5fbfd6a 100755 --- a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/AbstractActionSheetPicker.m +++ b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/AbstractActionSheetPicker.m @@ -165,7 +165,6 @@ - (instancetype)init { return self; } - - (void)setTextColor:(UIColor *)textColor { if (self.pickerTextAttributes) { self.pickerTextAttributes[NSForegroundColorAttributeName] = textColor; diff --git a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/ActionSheetDatePicker.m b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/ActionSheetDatePicker.m index 25174d92b..e77c2e8a1 100755 --- a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/ActionSheetDatePicker.m +++ b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/ActionSheetDatePicker.m @@ -27,19 +27,21 @@ #import "ActionSheetDatePicker.h" +#import "CoreActionSheetMonthYearPicker.h" #import @interface ActionSheetDatePicker() -@property (nonatomic, assign) UIDatePickerMode datePickerMode; +@property (nonatomic, assign) ActionSheetDatePickerMode datePickerMode; @property (nonatomic, strong) NSDate *selectedDate; @end @implementation ActionSheetDatePicker -@synthesize datePickerStyle = _datePickerStyle; +const CGFloat kActionSheetDefaultHeight = 216; +@synthesize datePickerStyle = _datePickerStyle; -(UIDatePickerStyle)datePickerStyle { if (_datePickerStyle != UIDatePickerStyleAutomatic) { @@ -50,7 +52,7 @@ -(UIDatePickerStyle)datePickerStyle { } + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin { ActionSheetDatePicker *picker = [[ActionSheetDatePicker alloc] initWithTitle:title datePickerMode:datePickerMode selectedDate:selectedDate target:target action:action origin:origin]; [picker showActionSheetPicker]; @@ -58,7 +60,7 @@ + (instancetype)showPickerWithTitle:(NSString *)title } + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin cancelAction:(SEL)cancelAction { ActionSheetDatePicker *picker = [[ActionSheetDatePicker alloc] initWithTitle:title datePickerMode:datePickerMode selectedDate:selectedDate target:target action:action origin:origin cancelAction:cancelAction]; [picker showActionSheetPicker]; @@ -66,7 +68,7 @@ + (instancetype)showPickerWithTitle:(NSString *)title } + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action origin:(id)origin { ActionSheetDatePicker *picker = [[ActionSheetDatePicker alloc] initWithTitle:title datePickerMode:datePickerMode selectedDate:selectedDate target:target action:action origin:origin]; @@ -77,7 +79,7 @@ + (instancetype)showPickerWithTitle:(NSString *)title } + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate doneBlock:(ActionDateDoneBlock)doneBlock cancelBlock:(ActionDateCancelBlock)cancelBlock @@ -94,7 +96,7 @@ + (instancetype)showPickerWithTitle:(NSString *)title } + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate @@ -114,13 +116,13 @@ + (instancetype)showPickerWithTitle:(NSString *)title return picker; } -- (id)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin +- (id)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin { self = [self initWithTitle:title datePickerMode:datePickerMode selectedDate:selectedDate target:target action:action origin:origin cancelAction:nil]; return self; } -- (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action origin:(id)origin +- (instancetype)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action origin:(id)origin { self = [self initWithTitle:title datePickerMode:datePickerMode selectedDate:selectedDate target:target action:action origin:origin cancelAction:nil]; self.minimumDate = minimumDate; @@ -128,7 +130,7 @@ - (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode return self; } -- (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin cancelAction:(SEL)cancelAction +- (instancetype)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin cancelAction:(SEL)cancelAction { self = [super initWithTarget:target successAction:action cancelAction:cancelAction origin:origin]; if (self) { @@ -139,7 +141,7 @@ - (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode return self; } -- (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action cancelAction:(SEL)cancelAction origin:(id)origin +- (instancetype)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action cancelAction:(SEL)cancelAction origin:(id)origin { self = [super initWithTarget:target successAction:action cancelAction:cancelAction origin:origin]; if (self) { @@ -153,7 +155,7 @@ - (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode } - (instancetype)initWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate doneBlock:(ActionDateDoneBlock)doneBlock cancelBlock:(ActionDateCancelBlock)cancelBlock @@ -167,10 +169,75 @@ - (instancetype)initWithTitle:(NSString *)title return self; } +- (CoreActionSheetMonthYearPickerMode) CoreActionSheetMonthYearPickerMode { + switch (self.datePickerMode) { + case ActionSheetDatePickerModeMonthAndYear: + return CoreActionSheetMonthYearPickerModeMonthAndYear; + case ActionSheetDatePickerModeYear: + return CoreActionSheetMonthYearPickerModeYear; + default: + return CoreActionSheetMonthYearPickerModeMonthAndYear; + } +} + +- (UIDatePickerMode) uiDatePickerMode { + switch (self.datePickerMode) { + case ActionSheetDatePickerModeTime: + return UIDatePickerModeTime; + case ActionSheetDatePickerModeDate: + return UIDatePickerModeDate; + case ActionSheetDatePickerModeDateAndTime: + return UIDatePickerModeDateAndTime; + case ActionSheetDatePickerModeCountDownTimer: + return UIDatePickerModeCountDownTimer; + default: + return UIDatePickerModeTime; + } +} + +- (BOOL) isSystemDatePicker { + switch (self.datePickerMode) { + case ActionSheetDatePickerModeTime: + case ActionSheetDatePickerModeDate: + case ActionSheetDatePickerModeDateAndTime: + case ActionSheetDatePickerModeCountDownTimer: + return YES; + case ActionSheetDatePickerModeMonthAndYear: + case ActionSheetDatePickerModeYear: + return NO; + } +} + - (UIView *)configuredPickerView { - CGRect datePickerFrame = CGRectMake(0, 40, self.viewSize.width, 216); - UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:datePickerFrame]; - datePicker.datePickerMode = self.datePickerMode; + UIView* datePicker; + if ([self isSystemDatePicker]) { + datePicker = [self createSystemDatePicker]; + } else { + datePicker = [self createCustomPicker]; + } + + //need to keep a reference to the picker so we can clear the DataSource / Delegate when dismissing (not used in this picker, but just in case somebody uses this as a template for another picker) + self.pickerView = datePicker; + + return datePicker; +} + +- (UIView*) createCustomPicker { + CoreActionSheetMonthYearPicker *datePicker = [[CoreActionSheetMonthYearPicker alloc] initWithFrame: CGRectMake(0, 40, self.viewSize.width, kActionSheetDefaultHeight)]; + datePicker.datePickerMode = [self CoreActionSheetMonthYearPickerMode]; + datePicker.maximumDate = self.maximumDate; + datePicker.minimumDate = self.minimumDate; + datePicker.calendar = self.calendar; + datePicker.locale = self.locale; + datePicker.pickerTextAttributes = self.pickerTextAttributes; + datePicker.date = self.selectedDate; + [datePicker addTarget:self action:@selector(eventForDatePicker:) forControlEvents:UIControlEventValueChanged]; + return datePicker; +} + +- (UIView*) createSystemDatePicker { + UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame: CGRectMake(0, 40, self.viewSize.width, kActionSheetDefaultHeight)]; + datePicker.datePickerMode = [self uiDatePickerMode]; datePicker.maximumDate = self.maximumDate; datePicker.minimumDate = self.minimumDate; datePicker.minuteInterval = self.minuteInterval; @@ -188,7 +255,7 @@ - (UIView *)configuredPickerView { // if datepicker is set with a date in countDownMode then // 1h is added to the initial countdown - if (self.datePickerMode == UIDatePickerModeCountDownTimer) { + if (self.datePickerMode == ActionSheetDatePickerModeCountDownTimer) { datePicker.countDownDuration = self.countDownDuration; // Due to a bug in UIDatePicker, countDownDuration needs to be set asynchronously // more info: http://stackoverflow.com/a/20204317/1161723 @@ -198,12 +265,9 @@ - (UIView *)configuredPickerView { } else { [datePicker setDate:self.selectedDate animated:NO]; } - + [datePicker addTarget:self action:@selector(eventForDatePicker:) forControlEvents:UIControlEventValueChanged]; - //need to keep a reference to the picker so we can clear the DataSource / Delegate when dismissing (not used in this picker, but just in case somebody uses this as a template for another picker) - self.pickerView = datePicker; - return datePicker; } @@ -211,7 +275,7 @@ - (void)notifyTarget:(id)target didSucceedWithAction:(SEL)action origin:(id)orig { if (self.onActionSheetDone) { - if (self.datePickerMode == UIDatePickerModeCountDownTimer) + if (self.datePickerMode == ActionSheetDatePickerModeCountDownTimer) self.onActionSheetDone(self, @(((UIDatePicker *)self.pickerView).countDownDuration), origin); else self.onActionSheetDone(self, self.selectedDate, origin); @@ -221,7 +285,7 @@ - (void)notifyTarget:(id)target didSucceedWithAction:(SEL)action origin:(id)orig else if ([target respondsToSelector:action]) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" - if (self.datePickerMode == UIDatePickerModeCountDownTimer) { + if (self.datePickerMode == ActionSheetDatePickerModeCountDownTimer) { [target performSelector:action withObject:@(((UIDatePicker *)self.pickerView).countDownDuration) withObject:origin]; } else { @@ -251,11 +315,21 @@ - (void)notifyTarget:(id)target didCancelWithAction:(SEL)cancelAction origin:(id - (void)eventForDatePicker:(id)sender { - if (!sender || ![sender isKindOfClass:[UIDatePicker class]]) + if (!sender) + return; + + if ([sender isKindOfClass:[UIDatePicker class]]) { + UIDatePicker *datePicker = (UIDatePicker *)sender; + self.selectedDate = datePicker.date; + self.countDownDuration = datePicker.countDownDuration; + return; + } + + if ([sender isKindOfClass:[CoreActionSheetMonthYearPicker class]]) { + CoreActionSheetMonthYearPicker *datePicker = (CoreActionSheetMonthYearPicker *)sender; + self.selectedDate = datePicker.date; return; - UIDatePicker *datePicker = (UIDatePicker *)sender; - self.selectedDate = datePicker.date; - self.countDownDuration = datePicker.countDownDuration; + } } - (void)customButtonPressed:(id)sender { @@ -270,10 +344,19 @@ - (void)customButtonPressed:(id)sender { case ActionTypeValue: { NSAssert([self.pickerView respondsToSelector:@selector(setDate:animated:)], @"Bad pickerView for ActionSheetDatePicker, doesn't respond to setDate:animated:"); NSDate *itemValue = buttonDetails[kButtonValue]; - UIDatePicker *picker = (UIDatePicker *)self.pickerView; - if (self.datePickerMode != UIDatePickerModeCountDownTimer) + id picker = self.pickerView; + if (self.datePickerMode != ActionSheetDatePickerModeCountDownTimer) { - [picker setDate:itemValue animated:YES]; + if ([picker isKindOfClass:[UIDatePicker class]]) { + UIDatePicker *datePicker = (UIDatePicker *)picker; + [datePicker setDate:itemValue animated:YES]; + } + + if ([picker isKindOfClass:[CoreActionSheetMonthYearPicker class]]) { + CoreActionSheetMonthYearPicker *datePicker = (CoreActionSheetMonthYearPicker *)picker; + [datePicker setDate:itemValue animated:YES]; + } + [self eventForDatePicker:picker]; } break; @@ -292,26 +375,28 @@ - (void)customButtonPressed:(id)sender { - (CGFloat)getDatePickerHeight { - CGFloat height = 216.0; + CGFloat height = kActionSheetDefaultHeight; + if ([self isSystemDatePicker]) { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 // Xcode 12 and iOS 14, or greater - if (@available(iOS 14.0, *)) { - if (_datePickerStyle == UIDatePickerStyleCompact) { - height = 90.0; - } else if (_datePickerStyle == UIDatePickerStyleInline) { - switch (_datePickerMode) { - case UIDatePickerModeDate: - height = 350.0; - break; - case UIDatePickerModeTime: - height = 90.0; - break; - default: // UIDatePickerModeDateAndTime - height = 400.0; - break; + if (@available(iOS 14.0, *)) { + if (_datePickerStyle == UIDatePickerStyleCompact) { + height = 90.0; + } else if (_datePickerStyle == UIDatePickerStyleInline) { + switch (_datePickerMode) { + case ActionSheetDatePickerModeDate: + height = 350.0; + break; + case ActionSheetDatePickerModeTime: + height = 90.0; + break; + default: // ActionSheetDatePickerModeDateAndTime + height = 400.0; + break; + } } } - } #endif + } return height; } diff --git a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/CoreActionSheetMonthYearPicker.m b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/CoreActionSheetMonthYearPicker.m new file mode 100644 index 000000000..7a5aff432 --- /dev/null +++ b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/CoreActionSheetMonthYearPicker.m @@ -0,0 +1,477 @@ +// +// CoreActionSheetMonthYearPicker.m +// CoreActionSheetPicker +// +// Created by Nguyen Truong Luu on 9/16/22. +// Copyright © 2022 Petr Korolev. All rights reserved. +// + +#import "CoreActionSheetMonthYearPicker.h" + +// +// CoreActionSheetMonthYearPickerViewDelegate +// + +@protocol CoreActionSheetMonthYearPickerViewDelegate +- (void)didSelectDate; +@end + +// +// CoreActionSheetMonthYearPickerView +// + +@interface CoreActionSheetMonthYearPickerView : UIPickerView + +@property (nonatomic) CoreActionSheetMonthYearPickerMode datePickerMode; +@property (nonatomic, retain) NSLocale *locale; +@property (nonatomic, copy) NSCalendar *calendar; +@property (nonatomic, retain) NSDate *date; +@property (nonatomic, retain) NSDate *minimumDate; +@property (nonatomic, retain) NSDate *maximumDate; +@property (nonatomic, retain) NSMutableDictionary *pickerTextAttributes; +@property (nonatomic, assign) id pickerDelegate; + +- (void)setDate:(NSDate *)date animated:(BOOL)animated; + +@end + +@implementation CoreActionSheetMonthYearPickerView { + // Picker data (list of months and years) + NSArray *_months; + NSArray *_years; + + // Cached min/max year/month values + // We do this to avoid expensive NSDateComponents-based date math in pickerView:viewForRow + NSInteger _minimumYear; + NSInteger _maximumYear; + NSInteger _minimumMonth; + NSInteger _maximumMonth; +} + +@synthesize datePickerMode; +@synthesize locale = _locale; +@synthesize calendar = _calendar; +@synthesize date = _date; +@synthesize minimumDate; +@synthesize maximumDate; +@synthesize pickerDelegate; + +// Default min/max year values used if minimumDate/maximumDate is not set +// These values match that of UIDatePicker +const NSInteger kMinYear = 1; +const NSInteger kMaxYear = 10000; + +#pragma mark - Initialization + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self initCommon]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + if (self) { + [self initCommon]; + } + return self; +} + +- (void)initCommon { + self.dataSource = self; + self.delegate = self; + self.showsSelectionIndicator = YES; + + // Initialize default cached values + [self initCachedValues]; + + // Initialize picker data + [self initPickerData]; + + // Set default date to today + _date = [NSDate date]; +} + +- (void)initCachedValues { + _minimumYear = -1; + _maximumYear = -1; + _minimumMonth = -1; + _maximumMonth = -1; +} + +- (void)initPickerData { + // Form list of months + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setLocale:self.locale]; + _months = [dateFormatter monthSymbols]; + + // Form list of years + [dateFormatter setDateFormat:@"yyyy"]; + NSDateComponents *comps = [[NSDateComponents alloc] init]; + + NSMutableArray *years = [[NSMutableArray alloc] init]; + for( int year = kMinYear ; year <= kMaxYear ; ++year ) { + [comps setYear:year]; + NSDate *yearDate = [self.calendar dateFromComponents:comps]; + NSString *yearStr = [dateFormatter stringFromDate:yearDate]; + + [years addObject:yearStr]; + } + _years = years; +} + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + // Set initial picker selection + [self selectionFromDate:NO]; +} + +#pragma mark - Date picker mode + +- (void)setDatePickerMode:(CoreActionSheetMonthYearPickerMode)mode { + datePickerMode = mode; + + [self reloadAllComponents]; + [self selectionFromDate:NO]; +} + +#pragma mark - Locale + +- (NSLocale *)locale { + if( _locale == nil ) { + _locale = [self.calendar locale]; + } + return _locale; +} + +- (void)setLocale:(NSLocale *)loc { + _locale = loc; +} + +#pragma mark - Calendar + +- (NSCalendar *)calendar { + if( _calendar == nil ) { + _calendar = [NSCalendar currentCalendar]; + } + return _calendar; +} + +- (void)setCalendar:(NSCalendar *)cal { + _calendar = cal; +} + +#pragma mark - Date + +- (NSDate *)date { + return _date; +} + +- (void)setDate:(NSDate *)dt { + [self setDate:dt animated:NO]; +} + +- (void)setDate:(NSDate *)dt animated:(BOOL)animated { + _date = dt; + [self selectionFromDate:animated]; +} + +#pragma mark - Min / Max date + +- (void)setMinimumDate:(NSDate *)minDate { + minimumDate = minDate; + + // Pre-calculate min year & month + if( minimumDate != nil ) { + NSDateComponents *comps = [self.calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth) fromDate:minimumDate]; + _minimumYear = comps.year; + _minimumMonth = comps.month; + } else { + _minimumYear = -1; + _minimumMonth = -1; + } + + [self reloadAllComponents]; +} + +- (void)setMaximumDate:(NSDate *)maxDate { + maximumDate = maxDate; + + // Pre-calculate max year & month + if( maximumDate != nil ) { + NSDateComponents *comps = [self.calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth) fromDate:maximumDate]; + _maximumYear = comps.year; + _maximumMonth = comps.month; + } else { + _maximumYear = -1; + _maximumMonth = -1; + } + + [self reloadAllComponents]; +} + +- (void)setPickerTextAttributes:(NSMutableDictionary *)attributes { + _pickerTextAttributes = attributes; + + [self reloadAllComponents]; +} + +#pragma mark - Date <-> selection + +- (void)selectionFromDate:(BOOL)animated { + // Extract the month and year from the current date value + NSDateComponents* comps = [self.calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth) fromDate:self.date]; + NSInteger month = [comps month]; + NSInteger year = [comps year]; + + // Select the corresponding rows in the UI + if( datePickerMode == CoreActionSheetMonthYearPickerModeYear ) { + [self selectRow:(year - kMinYear) inComponent:0 animated:animated]; + } else { + [self selectRow:(month - 1) inComponent:0 animated:animated]; + [self selectRow:(year - kMinYear) inComponent:1 animated:animated]; + } +} + +- (NSDate *)dateFromSelection { + NSInteger month, year; + + // Get the currently selected month and year + if( datePickerMode == CoreActionSheetMonthYearPickerModeYear ) { + month = 1; + year = [self selectedRowInComponent:0] + kMinYear; + } else { + month = [self selectedRowInComponent:0] + 1; + year = [self selectedRowInComponent:1] + kMinYear; + } + + // Assemble into a date object + NSDateComponents *comps = [[NSDateComponents alloc] init]; + [comps setDay:1]; + [comps setMonth:month]; + [comps setYear:year]; + + return [self.calendar dateFromComponents:comps]; +} + +#pragma mark - UIPickerViewDataSource + +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { + return (datePickerMode == CoreActionSheetMonthYearPickerModeYear) ? 1 : 2; +} + +- (NSInteger)pickerView:(UIPickerView *)pickerView +numberOfRowsInComponent:(NSInteger)component { + BOOL isYearComponent = (datePickerMode == CoreActionSheetMonthYearPickerModeYear) || (component == 1); + return isYearComponent ? [_years count] : [_months count]; +} + +#pragma mark - UIPickerViewDelegate + +- (UIView *)pickerView:(UIPickerView *)pickerView + viewForRow:(NSInteger)row + forComponent:(NSInteger)component + reusingView:(UIView *)view { + // Create (or reuse) the label instance + UILabel *label = (UILabel *)view; + if( label == nil ) { + CGSize rowSize = [pickerView rowSizeForComponent:component]; + label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, rowSize.width, rowSize.height)]; + label.adjustsFontSizeToFitWidth = YES; + } + + // Is this the year component? + BOOL isYearComponent = (datePickerMode == CoreActionSheetMonthYearPickerModeYear) || (component == 1); + + // Is the month or year represented by this component out of bounds? (i.e. < min or > max) + BOOL outOfBounds = NO; + if( isYearComponent ) { + NSInteger year = row + kMinYear; + + if( ((maximumDate != nil) && (year > _maximumYear)) || + ((minimumDate != nil) && (year < _minimumYear)) ) { + outOfBounds = YES; + } + } else { + NSInteger month = row + 1; + + // Extract the year from the current date + NSDateComponents *comps = [self.calendar components:(NSCalendarUnitYear) fromDate:self.date]; + NSInteger year = comps.year; + + if( ( (maximumDate != nil) && ((year > _maximumYear) || ((year == _maximumYear) && (month > _maximumMonth))) ) || + ( (minimumDate != nil) && ((year < _minimumYear) || ((year == _minimumYear) && (month < _minimumMonth))) ) ) { + outOfBounds = YES; + } + } + + // Set label text & color + label.attributedText = [[NSAttributedString alloc] initWithString: [(isYearComponent ? _years : _months) objectAtIndex:row] attributes: self.pickerTextAttributes]; + label.textColor = (outOfBounds ? [UIColor grayColor] : [UIColor blackColor]); + + return label; +} + +- (void)pickerView:(UIPickerView *)pickerView + didSelectRow:(NSInteger)row + inComponent:(NSInteger)component { + // Update date value + _date = [self dateFromSelection]; + + // If the currently selected date < the min date, reset it to the min date + if( (minimumDate != nil) && ([self compareMonthYear:self.date with:minimumDate] == NSOrderedAscending) ) { + [self setDate:minimumDate animated:YES]; + } + + // If the currently selected date > the min date, reset it to the max date + if( (maximumDate != nil) && ([self compareMonthYear:self.date with:maximumDate] == NSOrderedDescending) ) { + [self setDate:maximumDate animated:YES]; + } + + // If the year was changed, reload the month picker + // This is to refresh the enabled/disabled state of the months + BOOL isYearComponent = (datePickerMode == CoreActionSheetMonthYearPickerModeYear) || (component == 1); + if( isYearComponent ) { + [self reloadComponent:0]; + } + + // Notify delegate + [pickerDelegate didSelectDate]; +} + +- (NSComparisonResult)compareMonthYear:(NSDate *)date1 with:(NSDate *)date2 { + NSDateComponents *comps = [self.calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth) fromDate:date1]; + date1 = [self.calendar dateFromComponents:comps]; + + comps = [self.calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth) fromDate:date2]; + date2 = [self.calendar dateFromComponents:comps]; + + return [date1 compare:date2]; +} + +@end + +// +// CoreActionSheetMonthYearPicker +// + +@interface CoreActionSheetMonthYearPicker (Delegate) +@end + +@implementation CoreActionSheetMonthYearPicker { + CoreActionSheetMonthYearPickerView *_pickerView; +} + +@synthesize datePickerMode; +@synthesize locale; +@synthesize calendar; +@synthesize date; +@synthesize minimumDate; +@synthesize maximumDate; +@synthesize pickerTextAttributes; + +#pragma mark - Initialization + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _pickerView = [[CoreActionSheetMonthYearPickerView alloc] initWithFrame: self.bounds]; + [self initCommon]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + if (self) { + _pickerView = [[CoreActionSheetMonthYearPickerView alloc] initWithCoder:aDecoder]; + CGSize pickerSize = [_pickerView sizeThatFits:CGSizeZero]; + _pickerView.frame = CGRectMake( 0, 0, pickerSize.width, pickerSize.height ); + [self initCommon]; + } + return self; +} + +- (void)initCommon { + self.frame = CGRectMake(self.frame.origin.x, + self.frame.origin.y, + _pickerView.frame.size.width, + _pickerView.frame.size.height); + _pickerView.pickerDelegate = self; + [self addSubview:_pickerView]; +} + +- (CGSize)sizeThatFits:(CGSize)size { + return [_pickerView sizeThatFits:size]; +} + +- (void)didSelectDate { + [self sendActionsForControlEvents:UIControlEventValueChanged]; +} + +#pragma mark - CoreActionSheetMonthYearPicker API + +- (CoreActionSheetMonthYearPickerMode)datePickerMode { + return _pickerView.datePickerMode; +} + +- (void)setDatePickerMode:(CoreActionSheetMonthYearPickerMode)dpm { + _pickerView.datePickerMode = dpm; +} + +- (NSLocale *)locale { + return _pickerView.locale; +} + +- (void)setLocale:(NSLocale *)loc { + _pickerView.locale = loc; +} + +- (NSCalendar *)calendar { + return _pickerView.calendar; +} + +- (void)setCalendar:(NSCalendar *)cal { + _pickerView.calendar = cal; +} + +- (NSDate *)date { + return _pickerView.date; +} + +- (void)setDate:(NSDate *)dt { + [_pickerView setDate:dt]; +} + +- (void)setDate:(NSDate *)dt animated:(BOOL)animated { + [_pickerView setDate:dt animated:animated]; +} + +- (NSDate *)minimumDate { + return _pickerView.minimumDate; +} + +- (void)setMinimumDate:(NSDate *)minDate { + _pickerView.minimumDate = minDate; +} + +- (NSDate *)maximumDate { + return _pickerView.maximumDate; +} + +- (void)setMaximumDate:(NSDate *)maxDate { + _pickerView.maximumDate = maxDate; +} + +- (NSMutableDictionary *)pickerTextAttributes { + return _pickerView.pickerTextAttributes; +} + +- (void)setPickerTextAttributes:(NSMutableDictionary *)attributes { + _pickerView.pickerTextAttributes = attributes; +} + +@end diff --git a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/ActionSheetDatePicker.h b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/ActionSheetDatePicker.h index b5a1090da..eaf3e3f43 100755 --- a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/ActionSheetDatePicker.h +++ b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/ActionSheetDatePicker.h @@ -27,10 +27,21 @@ #if COCOAPODS #import +#import #else #import +#import #endif +typedef enum { + ActionSheetDatePickerModeTime, + ActionSheetDatePickerModeDate, + ActionSheetDatePickerModeDateAndTime, + ActionSheetDatePickerModeCountDownTimer, + ActionSheetDatePickerModeMonthAndYear, + ActionSheetDatePickerModeYear +} ActionSheetDatePickerMode; + @class ActionSheetDatePicker; typedef void(^ActionDateDoneBlock)(ActionSheetDatePicker *picker, id selectedDate, id origin); //selectedDate is NSDate or NSNumber for "UIDatePickerModeCountDownTimer" @@ -55,14 +66,14 @@ typedef void(^ActionDateCancelBlock)(ActionSheetDatePicker *picker); @property (nonatomic, copy) ActionDateCancelBlock onActionSheetCancel; + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin; + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action @@ -70,7 +81,7 @@ typedef void(^ActionDateCancelBlock)(ActionSheetDatePicker *picker); cancelAction:(SEL)cancelAction; + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate @@ -79,14 +90,14 @@ typedef void(^ActionDateCancelBlock)(ActionSheetDatePicker *picker); origin:(id)origin; + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate doneBlock:(ActionDateDoneBlock)doneBlock cancelBlock:(ActionDateCancelBlock)cancelBlock origin:(UIView*)view; + (instancetype)showPickerWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate @@ -94,17 +105,17 @@ typedef void(^ActionDateCancelBlock)(ActionSheetDatePicker *picker); cancelBlock:(ActionDateCancelBlock)cancelBlock origin:(UIView*)view; -- (id)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin; +- (id)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin; -- (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action origin:(id)origin; +- (instancetype)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action origin:(id)origin; -- (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin cancelAction:(SEL)cancelAction; +- (instancetype)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate target:(id)target action:(SEL)action origin:(id)origin cancelAction:(SEL)cancelAction; -- (instancetype)initWithTitle:(NSString *)title datePickerMode:(UIDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action cancelAction:(SEL)cancelAction origin:(id)origin; +- (instancetype)initWithTitle:(NSString *)title datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate minimumDate:(NSDate *)minimumDate maximumDate:(NSDate *)maximumDate target:(id)target action:(SEL)action cancelAction:(SEL)cancelAction origin:(id)origin; - (instancetype)initWithTitle:(NSString *)title - datePickerMode:(UIDatePickerMode)datePickerMode + datePickerMode:(ActionSheetDatePickerMode)datePickerMode selectedDate:(NSDate *)selectedDate doneBlock:(ActionDateDoneBlock)doneBlock cancelBlock:(ActionDateCancelBlock)cancelBlock diff --git a/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/CoreActionSheetMonthYearPicker.h b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/CoreActionSheetMonthYearPicker.h new file mode 100644 index 000000000..aaaecfbcf --- /dev/null +++ b/CoreActionSheetPicker/CoreActionSheetPicker/Pickers/include/CoreActionSheetMonthYearPicker.h @@ -0,0 +1,51 @@ +// +// CoreActionSheetMonthYearPicker.h +// CoreActionSheetPicker +// +// Created by Nguyen Truong Luu on 9/16/22. +// Copyright © 2022 Petr Korolev. All rights reserved. +// + +#import + +typedef enum { + CoreActionSheetMonthYearPickerModeMonthAndYear, // Display month and year + CoreActionSheetMonthYearPickerModeYear // Display just the year +} CoreActionSheetMonthYearPickerMode; + +@interface CoreActionSheetMonthYearPicker : UIControl + +// The mode of the date picker - see the CoreActionSheetMonthYearPickerMode enum +// Default is CoreActionSheetMonthYearPickerModeMonthAndYear +@property (nonatomic) CoreActionSheetMonthYearPickerMode datePickerMode; + +// The locale used by the date picker +// Default is [NSLocale currentLocale]. Setting nil returns to default +@property (nonatomic, retain) NSLocale *locale; + +// The calendar to use for the date picker +// Default is [NSCalendar currentCalendar]. Setting nil returns to default +@property (nonatomic, copy) NSCalendar *calendar; + +// The date displayed by the date picker +// Default is current date when picker is created +@property (nonatomic, retain) NSDate *date; + +// The minimum date that the date picker should show +// Default is nil (Jan 1, 0001 in the UI) +@property (nonatomic, retain) NSDate *minimumDate; + +// The maximum date that the date picker should show +// Default is nil (Dec 31, 10000 in the UI) +@property (nonatomic, retain) NSDate *maximumDate; + +// Used to specify Picker Label attributes. +// Default with a NSMutableParagraphStyle to set label align center. +@property (nonatomic, retain) NSMutableDictionary *pickerTextAttributes; + +// Sets the date to display in the date picker +// If animated is YES, animate the wheels to display the new date +- (void)setDate:(NSDate *)date animated:(BOOL)animated; + +@end + diff --git a/Example Projects/Swift-Example/Swift-Example/Base.lproj/Main.storyboard b/Example Projects/Swift-Example/Swift-Example/Base.lproj/Main.storyboard index bfb99ecf7..e30bf28da 100644 --- a/Example Projects/Swift-Example/Swift-Example/Base.lproj/Main.storyboard +++ b/Example Projects/Swift-Example/Swift-Example/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -19,13 +19,13 @@ - + - + + + + + + + + + + + + + + + + + + + + + + - + -