diff --git a/Bohr.podspec b/Bohr.podspec index 6232846..1a895d4 100755 --- a/Bohr.podspec +++ b/Bohr.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Bohr" - s.version = "3.0.0-alpha.1" + s.version = "3.0.0-alpha.2" s.summary = "Settings screen composing framework" s.homepage = "https://github.com/DavdRoman/Bohr" s.author = { "David Román" => "d@vidroman.me" } diff --git a/Bohr.xcodeproj/project.pbxproj b/Bohr.xcodeproj/project.pbxproj index fa1b475..4c55418 100644 --- a/Bohr.xcodeproj/project.pbxproj +++ b/Bohr.xcodeproj/project.pbxproj @@ -34,6 +34,10 @@ 75E19B451B2BC76100C03FF6 /* BOChoiceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 754E56A31B20D2FE00075B6E /* BOChoiceTableViewCell.m */; }; 75E19B461B2BCCFE00C03FF6 /* BOTextTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 75E02FE11B21F72C009698D3 /* BOTextTableViewCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; 75E19B471B2BCCFE00C03FF6 /* BOTextTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 75E02FE21B21F72C009698D3 /* BOTextTableViewCell.m */; }; + D594623C1B90E17D0028F4BD /* BODateTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = D594623A1B90E17D0028F4BD /* BODateTableViewCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D594623D1B90E17D0028F4BD /* BODateTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D594623B1B90E17D0028F4BD /* BODateTableViewCell.m */; }; + D59462401B90EA5F0028F4BD /* UILabel+DatePickerCustomization.h in Headers */ = {isa = PBXBuildFile; fileRef = D594623E1B90EA5F0028F4BD /* UILabel+DatePickerCustomization.h */; }; + D59462411B90EA5F0028F4BD /* UILabel+DatePickerCustomization.m in Sources */ = {isa = PBXBuildFile; fileRef = D594623F1B90EA5F0028F4BD /* UILabel+DatePickerCustomization.m */; }; D5CF66461B8DFAC800FC5F13 /* BOTableViewSection.h in Headers */ = {isa = PBXBuildFile; fileRef = D5CF66441B8DFAC800FC5F13 /* BOTableViewSection.h */; settings = {ATTRIBUTES = (Public, ); }; }; D5CF66471B8DFAC800FC5F13 /* BOTableViewSection.m in Sources */ = {isa = PBXBuildFile; fileRef = D5CF66451B8DFAC800FC5F13 /* BOTableViewSection.m */; }; D5CF664C1B8DFF4700FC5F13 /* MZAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = D5CF66481B8DFF4700FC5F13 /* MZAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -103,6 +107,10 @@ 75C7AE261B1AB42A0050C8AA /* BOTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BOTableViewCell.m; sourceTree = ""; }; 75E02FE11B21F72C009698D3 /* BOTextTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BOTextTableViewCell.h; sourceTree = ""; }; 75E02FE21B21F72C009698D3 /* BOTextTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BOTextTableViewCell.m; sourceTree = ""; }; + D594623A1B90E17D0028F4BD /* BODateTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BODateTableViewCell.h; sourceTree = ""; }; + D594623B1B90E17D0028F4BD /* BODateTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BODateTableViewCell.m; sourceTree = ""; }; + D594623E1B90EA5F0028F4BD /* UILabel+DatePickerCustomization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UILabel+DatePickerCustomization.h"; sourceTree = ""; }; + D594623F1B90EA5F0028F4BD /* UILabel+DatePickerCustomization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UILabel+DatePickerCustomization.m"; sourceTree = ""; }; D5CF66441B8DFAC800FC5F13 /* BOTableViewSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BOTableViewSection.h; sourceTree = ""; }; D5CF66451B8DFAC800FC5F13 /* BOTableViewSection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BOTableViewSection.m; sourceTree = ""; }; D5CF66481B8DFF4700FC5F13 /* MZAppearance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MZAppearance.h; sourceTree = ""; }; @@ -191,6 +199,10 @@ D5F1D8A81B3A1EF1004DA018 /* BOTableViewController+Private.h */, D5CF66441B8DFAC800FC5F13 /* BOTableViewSection.h */, D5CF66451B8DFAC800FC5F13 /* BOTableViewSection.m */, + D5CF66481B8DFF4700FC5F13 /* MZAppearance.h */, + D5CF66491B8DFF4700FC5F13 /* MZAppearance.m */, + D5CF664A1B8DFF4700FC5F13 /* NSInvocation+Copy.h */, + D5CF664B1B8DFF4700FC5F13 /* NSInvocation+Copy.m */, 75C7AE251B1AB42A0050C8AA /* BOTableViewCell.h */, 75C7AE261B1AB42A0050C8AA /* BOTableViewCell.m */, D5D00B711B8FE63E00ADCAB2 /* BOTableViewCell+Private.h */, @@ -199,6 +211,10 @@ 754E568C1B1FC16700075B6E /* BOSwitchTableViewCell.m */, 75E02FE11B21F72C009698D3 /* BOTextTableViewCell.h */, 75E02FE21B21F72C009698D3 /* BOTextTableViewCell.m */, + D594623A1B90E17D0028F4BD /* BODateTableViewCell.h */, + D594623B1B90E17D0028F4BD /* BODateTableViewCell.m */, + D594623E1B90EA5F0028F4BD /* UILabel+DatePickerCustomization.h */, + D594623F1B90EA5F0028F4BD /* UILabel+DatePickerCustomization.m */, 754E56931B2083DE00075B6E /* BOTimeTableViewCell.h */, 754E56941B2083DE00075B6E /* BOTimeTableViewCell.m */, 754E56A21B20D2FE00075B6E /* BOChoiceTableViewCell.h */, @@ -210,10 +226,6 @@ 754E56871B1DFDB400075B6E /* BOSetting.h */, 754E56881B1DFDB400075B6E /* BOSetting.m */, D5F1D8AA1B3A210E004DA018 /* BOSetting+Private.h */, - D5CF66481B8DFF4700FC5F13 /* MZAppearance.h */, - D5CF66491B8DFF4700FC5F13 /* MZAppearance.m */, - D5CF664A1B8DFF4700FC5F13 /* NSInvocation+Copy.h */, - D5CF664B1B8DFF4700FC5F13 /* NSInvocation+Copy.m */, 75C7AE011B1AB3280050C8AA /* Supporting Files */, ); path = Bohr; @@ -235,6 +247,7 @@ buildActionMask = 2147483647; files = ( D5F1D8AB1B3A210E004DA018 /* BOSetting+Private.h in Headers */, + D59462401B90EA5F0028F4BD /* UILabel+DatePickerCustomization.h in Headers */, 754E56501B1B461700075B6E /* BOTableViewCell+Subclass.h in Headers */, 75E19B461B2BCCFE00C03FF6 /* BOTextTableViewCell.h in Headers */, 75C7AE041B1AB3280050C8AA /* Bohr.h in Headers */, @@ -251,6 +264,7 @@ 759E1B001B2BC31700AD8F38 /* BOTimeTableViewCell.h in Headers */, 75B6CE1E1B375DCA00DADCBD /* BOButtonTableViewCell.h in Headers */, D5F1D8A91B3A1EF1004DA018 /* BOTableViewController+Private.h in Headers */, + D594623C1B90E17D0028F4BD /* BODateTableViewCell.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -373,7 +387,9 @@ 75B6CE1F1B375DCA00DADCBD /* BOButtonTableViewCell.m in Sources */, D5CF66471B8DFAC800FC5F13 /* BOTableViewSection.m in Sources */, 754E568E1B1FC16700075B6E /* BOSwitchTableViewCell.m in Sources */, + D594623D1B90E17D0028F4BD /* BODateTableViewCell.m in Sources */, 759E1B011B2BC31700AD8F38 /* BOTimeTableViewCell.m in Sources */, + D59462411B90EA5F0028F4BD /* UILabel+DatePickerCustomization.m in Sources */, D5CF664D1B8DFF4700FC5F13 /* MZAppearance.m in Sources */, 75B6CE1D1B3756D800DADCBD /* BOOptionTableViewCell.m in Sources */, 75E19B471B2BCCFE00C03FF6 /* BOTextTableViewCell.m in Sources */, diff --git a/Bohr/BODateTableViewCell.h b/Bohr/BODateTableViewCell.h new file mode 100644 index 0000000..630e25f --- /dev/null +++ b/Bohr/BODateTableViewCell.h @@ -0,0 +1,16 @@ +// +// BODateTableViewCell.h +// Bohr +// +// Created by David Román Aguirre on 28/08/15. +// +// + +#import "BOTableViewCell.h" + +@interface BODateTableViewCell : BOTableViewCell + +@property (nonatomic, assign) NSString *dateFormat; +@property (nonatomic) UIDatePicker *datePicker; + +@end diff --git a/Bohr/BODateTableViewCell.m b/Bohr/BODateTableViewCell.m new file mode 100644 index 0000000..c3d66e7 --- /dev/null +++ b/Bohr/BODateTableViewCell.m @@ -0,0 +1,61 @@ +// +// BODateTableViewCell.m +// Bohr +// +// Created by David Román Aguirre on 28/08/15. +// +// + +#import "BODateTableViewCell.h" + +#import "BOTableViewCell+Subclass.h" +#import "UILabel+DatePickerCustomization.h" + +@interface BODateTableViewCell () + +@property (nonatomic) NSDateFormatter *dateFormatter; + +@end + +@implementation BODateTableViewCell + +- (void)setup { + self.datePicker = [UIDatePicker new]; + self.datePicker.backgroundColor = [UIColor clearColor]; + self.datePicker.datePickerMode = UIDatePickerModeDate; + [self.datePicker addTarget:self action:@selector(datePickerValueDidChange) forControlEvents:UIControlEventValueChanged]; + self.expansionView = self.datePicker; + + self.dateFormatter = [NSDateFormatter new]; + self.dateFormatter.dateFormat = [self defaultDateFormat]; +} + +- (CGFloat)expansionHeight { + // Uncomment if the picker view doesn't show on iOS 9. + // return 216; + return [super expansionHeight]; +} + +- (void)setDateFormat:(NSString *)dateFormat { + dateFormat = self.dateFormat.length == 0 ? [self defaultDateFormat] : dateFormat; + self.dateFormatter.dateFormat = dateFormat; +} + +- (NSString *)dateFormat { + return self.dateFormatter.dateFormat; +} + +- (NSString *)defaultDateFormat { + return [NSDateFormatter dateFormatFromTemplate:@"dd/MM/YYYY" options:kNilOptions locale:[NSLocale currentLocale]]; +} + +- (void)settingValueDidChange { + self.detailTextLabel.text = [self.dateFormatter stringFromDate:self.setting.value]; + self.datePicker.date = self.setting.value; +} + +- (void)datePickerValueDidChange { + self.setting.value = self.datePicker.date; +} + +@end diff --git a/Bohr/BOTableViewCell+Subclass.h b/Bohr/BOTableViewCell+Subclass.h index eed957c..3212ee7 100644 --- a/Bohr/BOTableViewCell+Subclass.h +++ b/Bohr/BOTableViewCell+Subclass.h @@ -19,13 +19,16 @@ /// The setting object which the cell represents. @property (nonatomic) BOSetting *setting; +/// An optional view shown when the cell is pressed. +@property (nonatomic) UIView *expansionView; + /// The setup method for the cell, where you may set up all the views and constraints necessary for the cell to work. - (void)setup; /// The method in charge of updating the appearance of the main cell view components, through properties as mainColor, mainFont, secondaryColor, secondaryFont. - (void)updateAppearance; -/// You may return the height for the cell to be expanded when tapped. +/// The optional height for the cell to be expanded when pressed. - (CGFloat)expansionHeight; /// You may return the footer text for the cell to be set on its section. diff --git a/Bohr/BOTableViewCell.m b/Bohr/BOTableViewCell.m index ca84a8f..d4b01ef 100644 --- a/Bohr/BOTableViewCell.m +++ b/Bohr/BOTableViewCell.m @@ -31,6 +31,20 @@ - (instancetype)initWithTitle:(NSString *)title key:(NSString *)key handler:(voi return self; } +- (void)didMoveToSuperview { + if (self.superview && self.expansionView) { + [self.contentView addSubview:self.expansionView]; + + NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.expansionView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.expansionView.superview attribute:NSLayoutAttributeTopMargin multiplier:1 constant:0]; + NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.expansionView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.expansionView.superview attribute:NSLayoutAttributeLeft multiplier:1 constant:0]; + NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.expansionView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.expansionView.superview attribute:NSLayoutAttributeRight multiplier:1 constant:0]; + NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.expansionView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:[self expansionHeight]]; + + self.expansionView.translatesAutoresizingMaskIntoConstraints = NO; + [self.expansionView.superview addConstraints:@[topConstraint, leftConstraint, rightConstraint, heightConstraint]]; + } +} + - (void)setDestinationViewController:(UIViewController *)destinationViewController { if (_destinationViewController != destinationViewController) { _destinationViewController = destinationViewController; @@ -45,7 +59,7 @@ + (instancetype)cellWithTitle:(NSString *)title key:(NSString *)key handler:(voi - (void)layoutSubviews { [super layoutSubviews]; - if (self.expansionHeight > 0) { + if ([self expansionView]) { CGFloat yOffset = (self.layoutMargins.top-self.frame.size.height)/2; self.textLabel.center = CGPointMake(self.textLabel.center.x, self.textLabel.center.y+yOffset); @@ -73,7 +87,7 @@ - (void)_updateAppearance { - (void)setup {} - (void)setupConstraints {} - (void)updateAppearance {} -- (CGFloat)expansionHeight {return 0;} +- (CGFloat)expansionHeight {return self.expansionView.intrinsicContentSize.height;} - (NSString *)footerTitle {return nil;} - (void)wasSelectedFromViewController:(BOTableViewController *)viewController {} - (void)settingValueDidChange {} diff --git a/Bohr/BOTableViewController.m b/Bohr/BOTableViewController.m index c5fd617..8fddbb4 100644 --- a/Bohr/BOTableViewController.m +++ b/Bohr/BOTableViewController.m @@ -22,29 +22,37 @@ @interface BOTableViewController () @implementation BOTableViewController -- (instancetype)init { - return [self initWithStyle:UITableViewStyleGrouped]; +- (void)commonInit { + self.sections = [NSArray new]; + + self.tableView.estimatedRowHeight = 55; + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; + self.tableView.tableFooterView = [UIView new]; + + UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self.tableView action:@selector(endEditing:)]; + tapGestureRecognizer.cancelsTouchesInView = NO; + [self.tableView addGestureRecognizer:tapGestureRecognizer]; + + [self setup]; } - (instancetype)initWithStyle:(UITableViewStyle)style { if (self = [super initWithStyle:style]) { - self.sections = [NSArray new]; - - self.tableView.estimatedRowHeight = 55; - self.tableView.rowHeight = UITableViewAutomaticDimension; - self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; - self.tableView.tableFooterView = [UIView new]; - - UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self.tableView action:@selector(endEditing:)]; - tapGestureRecognizer.cancelsTouchesInView = NO; - [self.tableView addGestureRecognizer:tapGestureRecognizer]; - - [self setup]; + [self commonInit]; } return self; } +- (instancetype)init { + return [self initWithStyle:UITableViewStyleGrouped]; +} + +- (void)awakeFromNib { + [self commonInit]; +} + - (void)addSection:(BOTableViewSection *)section { self.sections = [self.sections arrayByAddingObject:section]; } @@ -92,7 +100,7 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { BOTableViewSection *section = self.sections[indexPath.section]; BOTableViewCell *cell = section.cells[indexPath.row]; - CGFloat cellHeight = [cell systemLayoutSizeFittingSize:CGSizeMake(cell.contentView.frame.size.width, 0)].height; + CGFloat cellHeight = [cell systemLayoutSizeFittingSize:CGSizeMake(cell.contentView.frame.size.width, UITableViewAutomaticDimension)].height; if (cellHeight < self.tableView.estimatedRowHeight) { cellHeight = self.tableView.estimatedRowHeight; @@ -113,6 +121,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N BOTableViewSection *section = self.sections[indexPath.section]; BOTableViewCell *cell = section.cells[indexPath.row]; cell.indexPath = indexPath; + [cell prepareForReuse]; if (cell.setting && !cell.setting.valueDidChangeBlock) { [UIView performWithoutAnimation:^{ @@ -143,7 +152,7 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(BOTableViewCell *)ce - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { BOTableViewCell *cell = (BOTableViewCell *)[tableView cellForRowAtIndexPath:indexPath]; - if (cell.expansionHeight > 0) { + if ([cell expansionHeight] > 0) { self.expansionIndexPath = ![indexPath isEqual:self.expansionIndexPath] ? indexPath : nil; [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; diff --git a/Bohr/BOTimeTableViewCell.h b/Bohr/BOTimeTableViewCell.h index 122b4d0..226c225 100644 --- a/Bohr/BOTimeTableViewCell.h +++ b/Bohr/BOTimeTableViewCell.h @@ -6,11 +6,8 @@ // Copyright (c) 2015 David Roman. All rights reserved. // -#import "BOTableViewCell.h" +#import "BODateTableViewCell.h" -@interface BOTimeTableViewCell : BOTableViewCell - -/// The minute interval showed on the time picker view. -@property (nonatomic) NSInteger minuteInterval; +@interface BOTimeTableViewCell : BODateTableViewCell @end diff --git a/Bohr/BOTimeTableViewCell.m b/Bohr/BOTimeTableViewCell.m index 804050a..0896f2e 100644 --- a/Bohr/BOTimeTableViewCell.m +++ b/Bohr/BOTimeTableViewCell.m @@ -10,143 +10,13 @@ #import "BOTableViewCell+Subclass.h" -@interface BOTimeTableViewCell () - -@property (nonatomic) UIPickerView *timePickerView; - -@end - @implementation BOTimeTableViewCell - (void)setup { - self.timePickerView = [UIPickerView new]; - self.timePickerView.backgroundColor = [UIColor clearColor]; - self.timePickerView.dataSource = self; - self.timePickerView.delegate = self; - [self.contentView addSubview:self.timePickerView]; - - NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.timePickerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.timePickerView.superview attribute:NSLayoutAttributeTopMargin multiplier:1 constant:0]; - NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.timePickerView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.timePickerView.superview attribute:NSLayoutAttributeLeft multiplier:1 constant:0]; - NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.timePickerView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.timePickerView.superview attribute:NSLayoutAttributeRight multiplier:1 constant:0]; - NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.timePickerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:216]; - - self.timePickerView.translatesAutoresizingMaskIntoConstraints = NO; - [self.timePickerView.superview addConstraints:@[topConstraint, leftConstraint, rightConstraint, heightConstraint]]; -} - -- (void)updateAppearance { - [self.timePickerView reloadAllComponents]; -} - -- (CGFloat)expansionHeight { - return self.timePickerView.frame.size.height; -} - -#pragma mark UIPickerViewDataSource - -- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { - return 2; -} - -- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { - switch (component) { - case 0: - return 24; - case 1: - return 60/self.minuteInterval; - } - - return 0; -} - -#pragma mark UIPickerViewDelegate - -- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component { - return 65; -} - -- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view { - NSString *title; - - switch (component) { - case 0: - title = [NSString stringWithFormat:@"%@%li", row < 10 ? @"0" : @"", (long)row]; - break; - - case 1: - title = [NSString stringWithFormat:@"%@%li", row*self.minuteInterval < 10 ? @"0" : @"", (long)(row*self.minuteInterval)]; - break; - } - - UILabel *label = (UILabel *)view; + [super setup]; - if (!label) { - label = [UILabel new]; - label.textAlignment = NSTextAlignmentCenter; - - if (self.mainColor) { - label.textColor = self.mainColor; - } - - UIFont *font = self.secondaryFont ? self.secondaryFont : [UIFont systemFontOfSize:[UIFont systemFontSize]]; - - CGSize size = [title sizeWithAttributes:@{NSFontAttributeName: font}]; - - // For current font point size, calculate points per pixel - CGFloat pointsPerPixel = font.pointSize/size.height; - - // Scale up point size for the height of the label - CGFloat desiredPointSize = 28*pointsPerPixel; - - label.font = [font fontWithSize:desiredPointSize]; - } - - label.text = title; - - return label; -} - -- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { - self.setting.value = @([self timeIntervalForTimePickerView]); -} - -- (NSInteger)timeIntervalForTimePickerView { - return 60*[self hoursForTimePickerView]+[self minutesForTimePickerView]; -} - -- (NSInteger)hoursForTimePickerView { - return [self.timePickerView selectedRowInComponent:0]; -} - -- (NSInteger)minutesForTimePickerView { - return [self.timePickerView selectedRowInComponent:1]*self.minuteInterval; -} - -- (void)settingValueDidChange { - self.detailTextLabel.text = [self timeStringForSettingValue]; - - [self.timePickerView selectRow:[self hoursForSettingValue] inComponent:0 animated:YES]; - [self.timePickerView selectRow:[self minutesForSettingValue]/self.minuteInterval inComponent:1 animated:YES]; -} - -- (NSString *)timeStringForSettingValue { - NSInteger hours = [self hoursForSettingValue]; - NSInteger minutes = [self minutesForSettingValue]; - - NSString *hoursString = [[NSString alloc] initWithFormat:@"%@%li", hours < 10 ? @"0" : @"", (long)hours]; - NSString *minutesString = [[NSString alloc] initWithFormat:@"%@%li", minutes < 10 ? @"0" : @"", (long)minutes]; - - NSString *timeString = [[NSString alloc] initWithFormat:@"%@:%@", hoursString, minutesString]; - - return timeString; -} - -- (NSInteger)hoursForSettingValue { - return floorf([self.setting.value integerValue]/60); -} - -- (NSInteger)minutesForSettingValue { - return (NSInteger)[self.setting.value integerValue] % 60; + self.dateFormat = [NSDateFormatter dateFormatFromTemplate:@"hh:mm" options:kNilOptions locale:[NSLocale currentLocale]]; + self.datePicker.datePickerMode = UIDatePickerModeTime; } @end diff --git a/Bohr/Bohr.h b/Bohr/Bohr.h index 84c05a2..9f60b73 100644 --- a/Bohr/Bohr.h +++ b/Bohr/Bohr.h @@ -20,6 +20,7 @@ FOUNDATION_EXPORT const unsigned char BohrVersionString[]; #import #import +#import #import #import #import diff --git a/Bohr/UILabel+DatePickerCustomization.h b/Bohr/UILabel+DatePickerCustomization.h new file mode 100644 index 0000000..a45c103 --- /dev/null +++ b/Bohr/UILabel+DatePickerCustomization.h @@ -0,0 +1,13 @@ +// +// UILabel+DatePickerCustomization.h +// Bohr +// +// Created by David Román Aguirre on 28/08/15. +// +// + +#import + +@interface UILabel (DatePickerCustomization) + +@end diff --git a/Bohr/UILabel+DatePickerCustomization.m b/Bohr/UILabel+DatePickerCustomization.m new file mode 100644 index 0000000..33707ef --- /dev/null +++ b/Bohr/UILabel+DatePickerCustomization.m @@ -0,0 +1,97 @@ +// +// UILabel+DatePickerCustomization.m +// Bohr +// +// Created by David Román Aguirre on 28/08/15. +// Built from this amazing comment from StackOverflow http://stackoverflow.com/a/21084227/5278228 +// + +#import "UILabel+DatePickerCustomization.h" +#import + +#import "BODateTableViewCell.h" + +@implementation UILabel (DatePickerCustomization) + ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [self swizzleInstanceSelector:@selector(setTextColor:) withSelector:@selector(bo_setTextColor:)]; + [self swizzleInstanceSelector:@selector(setFont:) withSelector:@selector(bo_setFont:)]; + [self swizzleInstanceSelector:@selector(willMoveToSuperview:) withSelector:@selector(bo_willMoveToSuperview:)]; + }); +} + ++ (void)swizzleInstanceSelector:(SEL)originalSelector withSelector:(SEL)newSelector { + Method originalMethod = class_getInstanceMethod(self, originalSelector); + Method newMethod = class_getInstanceMethod(self, newSelector); + + BOOL methodAdded = class_addMethod([self class], originalSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); + + if (methodAdded) { + class_replaceMethod([self class], newSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); + } else { + method_exchangeImplementations(originalMethod, newMethod); + } +} + +- (BOOL)view:(UIView *)view hasSuperviewOfClass:(Class)class { + if (view.superview) { + if ([view.superview isKindOfClass:class]){ + return YES; + } + + return [self view:view.superview hasSuperviewOfClass:class]; + } + + return NO; +} + +- (BOOL)belongsToDatePicker { + return [self view:self hasSuperviewOfClass:[UIDatePicker class]] || [self view:self hasSuperviewOfClass:NSClassFromString(@"UIDatePickerWeekMonthDayView")] || [self view:self hasSuperviewOfClass:NSClassFromString(@"UIDatePickerContentView")]; +} + +- (UIColor *)cellAppearanceMainColor { + return [BODateTableViewCell appearance].mainColor ? [BODateTableViewCell appearance].mainColor : [BOTableViewCell appearance].mainColor; +} + +- (UIFont *)cellAppearanceSecondaryFont { + return [BODateTableViewCell appearance].secondaryFont ? [BODateTableViewCell appearance].secondaryFont : [BOTableViewCell appearance].secondaryFont; +} + +// Forces the text colour & font for the UIDatePicker (if belongs to any). + +- (void)bo_setTextColor:(UIColor *)textColor { + textColor = [self belongsToDatePicker] ? [self cellAppearanceMainColor] : textColor; + [self bo_setTextColor:textColor]; +} + +- (void)bo_setFont:(UIFont *)font { + if ([self belongsToDatePicker]) { + + font = [self cellAppearanceSecondaryFont] ? [self cellAppearanceSecondaryFont] : font; + + CGSize size = [self.text sizeWithAttributes:@{NSFontAttributeName: font}]; + + // For current font point size, calculate points per pixel + CGFloat pointsPerPixel = font.pointSize/size.height; + + // Scale up point size for the height of the label + CGFloat desiredPointSize = 27*pointsPerPixel; + + font = [font fontWithSize:desiredPointSize]; + } + + [self bo_setFont:font]; +} + +// Some of the UILabels haven't been added to a superview yet so listen for when they do. +// This is just preventive code. You never know how the API may change in the future. + +- (void)bo_willMoveToSuperview:(UIView *)newSuperview { + [self bo_setTextColor:self.textColor]; + [self bo_setFont:self.font]; + [self bo_willMoveToSuperview:newSuperview]; +} + +@end diff --git a/BohrDemo/AppDelegate.m b/BohrDemo/AppDelegate.m index cc7ff5f..6a45a40 100644 --- a/BohrDemo/AppDelegate.m +++ b/BohrDemo/AppDelegate.m @@ -29,9 +29,10 @@ - (void)setupDefaults { @"bool_1": @YES, @"bool_2": @NO, @"text": @"", + @"date": [NSDate new], + @"time": [NSDate new], @"choice_1": @0, @"choice_2": @2, - @"time": @300, }]; } diff --git a/BohrDemo/TableViewController.m b/BohrDemo/TableViewController.m index aac304b..8d09a4d 100644 --- a/BohrDemo/TableViewController.m +++ b/BohrDemo/TableViewController.m @@ -15,7 +15,9 @@ - (void)setup { self.title = @"Bohr"; [self addSection:[BOTableViewSection sectionWithHeaderTitle:@"Section 1" handler:^(BOTableViewSection *section) { + [section addCell:[BOSwitchTableViewCell cellWithTitle:@"Switch 1" key:@"bool_1" handler:nil]]; + [section addCell:[BOSwitchTableViewCell cellWithTitle:@"Switch 2" key:@"bool_2" handler:^(BOSwitchTableViewCell *cell) { cell.onFooterTitle = @"Switch setting 2 is on"; cell.offFooterTitle = @"Switch setting 2 is off"; @@ -24,6 +26,7 @@ - (void)setup { __unsafe_unretained typeof(self) weakSelf = self; [self addSection:[BOTableViewSection sectionWithHeaderTitle:@"Section 2" handler:^(BOTableViewSection *section) { + [section addCell:[BOTextTableViewCell cellWithTitle:@"Text" key:@"text" handler:^(BOTextTableViewCell *cell) { cell.textField.placeholder = @"Placeholder"; cell.inputErrorBlock = ^(BOTextTableViewCell *cell, BOTextFieldInputError error) { @@ -31,8 +34,10 @@ - (void)setup { }; }]]; + [section addCell:[BODateTableViewCell cellWithTitle:@"Date" key:@"date" handler:nil]]; + [section addCell:[BOTimeTableViewCell cellWithTitle:@"Time" key:@"time" handler:^(BOTimeTableViewCell *cell) { - cell.minuteInterval = 5; + cell.datePicker.minuteInterval = 5; }]]; [section addCell:[BOChoiceTableViewCell cellWithTitle:@"Choice" key:@"choice_1" handler:^(BOChoiceTableViewCell *cell) { @@ -47,6 +52,7 @@ - (void)setup { }]]; [self addSection:[BOTableViewSection sectionWithHeaderTitle:@"Section 3" handler:^(BOTableViewSection *section) { + [section addCell:[BOButtonTableViewCell cellWithTitle:@"Button" key:nil handler:^(BOButtonTableViewCell *cell) { cell.actionBlock = ^{ [weakSelf showButtonAlert];