From ccc224349ee57827a7e748444f370d8fc7dcb7bb Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Tue, 21 Oct 2025 22:47:32 +0900 Subject: [PATCH 1/2] Add .clang-format file --- .clang-format | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..4429a9d --- /dev/null +++ b/.clang-format @@ -0,0 +1,87 @@ +--- +# iOS Objective-C Style Guide +# Based on Apple's coding conventions and common iOS practices + +BasedOnStyle: LLVM + +# Language specific settings +Language: ObjC + +# Indentation +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +ContinuationIndentWidth: 4 + +# Line length +ColumnLimit: 100 + +# Pointer and reference alignment +PointerAlignment: Right +ReferenceAlignment: Right + +# Braces +BreakBeforeBraces: Attach +AllowShortBlocksOnASingleLine: Empty +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: false + +# Method and function formatting +AlignAfterOpenBracket: Align +AllowAllParametersOfDeclarationOnNextLine: false +BinPackParameters: false +BinPackArguments: false + +# Objective-C specific +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true + +# Spacing +SpaceBeforeParens: ControlStatements +SpaceBeforeAssignmentOperators: true +SpaceAfterCStyleCast: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false + +# Keep things together +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 + +# Align consecutive assignments and declarations +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false + +# Comments +ReflowComments: true +SpacesBeforeTrailingComments: 2 + +# Line breaks +AllowShortCaseLabelsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true + +# Import/Include sorting +SortIncludes: CaseInsensitive +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*>' + Priority: 3 + +# Penalty weights (fine-tuning line breaks) +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 From 2cbef1b81cb795d160c8b46e707245aaa257e236 Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Tue, 21 Oct 2025 22:49:18 +0900 Subject: [PATCH 2/2] Run tidy on all of the source files --- .../Private/TOSegmentedControlSegment.h | 4 +- .../Private/TOSegmentedControlSegment.m | 135 ++-- TOSegmentedControl/TOSegmentedControl.h | 63 +- TOSegmentedControl/TOSegmentedControl.m | 705 +++++++++--------- 4 files changed, 470 insertions(+), 437 deletions(-) diff --git a/TOSegmentedControl/Private/TOSegmentedControlSegment.h b/TOSegmentedControl/Private/TOSegmentedControlSegment.h index 45eda09..3634e9a 100644 --- a/TOSegmentedControl/Private/TOSegmentedControlSegment.h +++ b/TOSegmentedControl/Private/TOSegmentedControlSegment.h @@ -72,7 +72,7 @@ NS_ASSUME_NONNULL_BEGIN /// Create an array of objects given an array of strings and images + (NSArray *)segmentsWithObjects:(NSArray *)objects - forSegmentedControl:(TOSegmentedControl *)segmentedControl;; + forSegmentedControl:(TOSegmentedControl *)segmentedControl; /// Create a non-reversible item from this class - (nullable instancetype)initWithObject:(id)object @@ -88,7 +88,7 @@ NS_ASSUME_NONNULL_BEGIN forSegmentedControl:(TOSegmentedControl *)segmentedControl; - (instancetype)initWithImage:(UIImage *)image reversible:(BOOL)reversible - forSegmentedControl:(TOSegmentedControl *)segmentedControl ; + forSegmentedControl:(TOSegmentedControl *)segmentedControl; /// If the item is reversible, flip the direction - (void)toggleDirection; diff --git a/TOSegmentedControl/Private/TOSegmentedControlSegment.m b/TOSegmentedControl/Private/TOSegmentedControlSegment.m index 26b5c11..10cac79 100644 --- a/TOSegmentedControl/Private/TOSegmentedControlSegment.m +++ b/TOSegmentedControl/Private/TOSegmentedControlSegment.m @@ -21,7 +21,9 @@ // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #import "TOSegmentedControlSegment.h" + #import "TOSegmentedControl.h" + #import // ------------------------------------------------- @@ -56,133 +58,125 @@ @implementation TOSegmentedControlSegment #pragma mark - Object Lifecyle - - (instancetype)initWithObject:(id)object - forSegmentedControl:(TOSegmentedControl *)segmentedControl -{ + forSegmentedControl:(TOSegmentedControl *)segmentedControl { if (![object isKindOfClass:NSString.class] && ![object isKindOfClass:UIImage.class]) { return nil; } - + if (self = [super init]) { if ([object isKindOfClass:NSString.class]) { _title = (NSString *)object; - } - else { + } else { _image = (UIImage *)object; } _segmentedControl = segmentedControl; [self commonInit]; } - + return self; } - (instancetype)initWithTitle:(NSString *)title - forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl -{ + forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl { if (self = [super init]) { _title = [title copy]; _segmentedControl = segmentedControl; [self commonInit]; } - + return self; } - (instancetype)initWithImage:(UIImage *)image - forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl -{ + forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl { if (self = [super init]) { _image = image; _segmentedControl = segmentedControl; [self commonInit]; } - + return self; } - (instancetype)initWithTitle:(NSString *)title reversible:(BOOL)reversible - forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl -{ + forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl { if (self = [super init]) { _title = [title copy]; _isReversible = reversible; _segmentedControl = segmentedControl; [self commonInit]; } - + return self; } - (instancetype)initWithImage:(UIImage *)image reversible:(BOOL)reversible - forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl -{ + forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl { if (self = [super init]) { _image = image; _isReversible = reversible; _segmentedControl = segmentedControl; [self commonInit]; } - + return self; } -- (void)dealloc -{ +- (void)dealloc { [self.itemView removeFromSuperview]; } #pragma mark - Comnvenience Initializers - -+ (NSArray *)segmentsWithObjects:(NSArray *)objects forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl -{ ++ (NSArray *)segmentsWithObjects:(NSArray *)objects + forSegmentedControl:(nonnull TOSegmentedControl *)segmentedControl { NSMutableArray *array = [NSMutableArray array]; - + // Create an object for each item in the array. // Skip anything that isn't an image or a label for (id object in objects) { TOSegmentedControlSegment *item = nil; if ([object isKindOfClass:NSString.class]) { item = [[TOSegmentedControlSegment alloc] initWithTitle:object - forSegmentedControl:segmentedControl]; - } - else if ([object isKindOfClass:UIImage.class]) { + forSegmentedControl:segmentedControl]; + } else if ([object isKindOfClass:UIImage.class]) { item = [[TOSegmentedControlSegment alloc] initWithImage:object - forSegmentedControl:segmentedControl]; + forSegmentedControl:segmentedControl]; } - if (item) { [array addObject:item]; } + if (item) { + [array addObject:item]; + } } - + return [NSArray arrayWithArray:array]; } #pragma mark - Set-up - -- (void)commonInit -{ +- (void)commonInit { // Create the container view _containerView = [[UIView alloc] init]; // Create the initial image / label view [self refreshItemView]; - + // Refresh the reversible state [self refreshReversibleView]; } #pragma mark - Reversible Management - -- (void)refreshReversibleView -{ +- (void)refreshReversibleView { // If we're no longer (Or never were) reversible, // hide and exit out if (!self.isReversible) { self.arrowView.hidden = YES; return; } - + // Create the arrow view if we haven't done so yet if (self.arrowView == nil && self.arrowImageView == nil) { UIImage *arrow = self.segmentedControl.arrowImage; @@ -191,7 +185,8 @@ - (void)refreshReversibleView [self.containerView addSubview:self.arrowView]; self.arrowImageView = [[UIImageView alloc] initWithImage:arrow]; - self.arrowImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.arrowImageView.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self.arrowView addSubview:self.arrowImageView]; } @@ -204,10 +199,11 @@ - (void)refreshReversibleView #pragma mark - View Management - -- (UILabel *)makeLabelForTitle:(NSString *)title -{ - if (title.length == 0) { return nil; } - +- (UILabel *)makeLabelForTitle:(NSString *)title { + if (title.length == 0) { + return nil; + } + // Object is a string. Create a label UILabel *label = [[UILabel alloc] init]; label.text = title; @@ -216,22 +212,20 @@ - (UILabel *)makeLabelForTitle:(NSString *)title label.font = self.segmentedControl.selectedTextFont; label.adjustsFontSizeToFitWidth = YES; label.minimumScaleFactor = 0.3f; - [label sizeToFit]; // Size to the selected font + [label sizeToFit]; // Size to the selected font label.font = self.segmentedControl.textFont; label.backgroundColor = [UIColor clearColor]; return label; } -- (UIImageView *)makeImageViewForImage:(UIImage *)image -{ +- (UIImageView *)makeImageViewForImage:(UIImage *)image { // Object is an image. Create an image view UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; imageView.tintColor = self.segmentedControl.itemColor; return imageView; } -- (void)refreshItemView -{ +- (void)refreshItemView { // Convenience check for whether the view is a label or image UIImageView *imageView = self.imageView; UILabel *label = self.label; @@ -241,34 +235,34 @@ - (void)refreshItemView if (imageView && self.image) { [(UIImageView *)self.itemView setImage:self.image]; } - + // If it's already a label, refresh the text if (label && self.title) { [(UILabel *)self.itemView setText:self.title]; } - + // If it's an image view, but the title text is set, swap them out if (!label && self.title) { [imageView removeFromSuperview]; imageView = nil; - + self.itemView = [self makeLabelForTitle:self.title]; [self.containerView addSubview:self.itemView]; - + label = (UILabel *)self.itemView; } - + // If it's a label view, but the image is set, swap them out if (!imageView && self.image) { [label removeFromSuperview]; label = nil; - + self.itemView = [self makeImageViewForImage:self.image]; [self.containerView addSubview:self.itemView]; - + imageView = (UIImageView *)self.itemView; } - + // Update the label view label.textColor = self.segmentedControl.itemColor; @@ -278,61 +272,58 @@ - (void)refreshItemView // Set back to default font label.font = self.segmentedControl.textFont; - + // Update the image view imageView.tintColor = self.segmentedControl.itemColor; } -- (void)toggleDirection -{ +- (void)toggleDirection { self.isReversed = !self.isReversed; } #pragma mark - Public Accessors - -- (void)setTitle:(NSString *)title -{ +- (void)setTitle:(NSString *)title { // Copy text, and regenerate the view if need be _title = [title copy]; _image = nil; [self refreshItemView]; } -- (void)setImage:(UIImage *)image -{ - if (_image == image) { return; } +- (void)setImage:(UIImage *)image { + if (_image == image) { + return; + } _image = image; _title = nil; [self refreshItemView]; } -- (void)setIsReversible:(BOOL)isReversible -{ - if (_isReversible == isReversible) { return; } +- (void)setIsReversible:(BOOL)isReversible { + if (_isReversible == isReversible) { + return; + } _isReversible = isReversible; [self refreshReversibleView]; } -- (UILabel *)label -{ +- (UILabel *)label { if ([self.itemView isKindOfClass:UILabel.class]) { return (UILabel *)self.itemView; } - + return nil; } -- (UIImageView *)imageView -{ +- (UIImageView *)imageView { if ([self.itemView isKindOfClass:UIImageView.class]) { return (UIImageView *)self.itemView; } - + return nil; } -- (void)setArrowImageReversed:(BOOL)reversed -{ +- (void)setArrowImageReversed:(BOOL)reversed { if (reversed) { self.arrowImageView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, M_PI); return; diff --git a/TOSegmentedControl/TOSegmentedControl.h b/TOSegmentedControl/TOSegmentedControl.h index ce3c80b..501c6a2 100644 --- a/TOSegmentedControl/TOSegmentedControl.h +++ b/TOSegmentedControl/TOSegmentedControl.h @@ -37,7 +37,8 @@ FOUNDATION_EXPORT const CGFloat TOSegmentendControlCapsuleCornerRadius; NS_SWIFT_NAME(SegmentedControl) IB_DESIGNABLE @interface TOSegmentedControl : UIControl -/// The items currently assigned to this segmented control. (Can be a combination of strings and images) +/// The items currently assigned to this segmented control. (Can be a combination of strings and +/// images) @property (nonatomic, copy, nullable) NSArray *items; /// A block that is called whenever a segment is tapped. @@ -55,7 +56,8 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// The index values of all of the segments that are reversible. @property (nonatomic, strong) NSArray *reversibleSegmentIndexes; -/// The amount of rounding in the corners (Default is 8.0f up to iOS 18, and the capsule radius on iOS 26) +/// The amount of rounding in the corners (Default is 8.0f up to iOS 18, and the capsule radius on +/// iOS 26) @property (nonatomic, assign) IBInspectable CGFloat cornerRadius; /// Set the background color of the track in the segmented control (Default is light grey) @@ -96,12 +98,12 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// @param items An array of either images, or strings to display - (instancetype)initWithItems:(nullable NSArray *)items NS_SWIFT_NAME(init(items:)); - /// Replaces the content of an existing segment with a new image. /// /// @param image The image to set. /// @param index The index of the segment to set. -- (void)setImage:(UIImage *)image forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:forSegmentAt:)); +- (void)setImage:(UIImage *)image + forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:forSegmentAt:)); /// Replaces the content of an existing segment with a new image, /// and optionally makes it reversible. @@ -109,8 +111,9 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// @param image The image to set. /// @param reversible Whether the item can be tapped multiple times to flip directions. /// @param index The index of the segment to set. -- (void)setImage:(UIImage *)image reversible:(BOOL)reversible - forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:reversible:forSegmentAt:)); +- (void)setImage:(UIImage *)image + reversible:(BOOL)reversible + forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:reversible:forSegmentAt:)); /// Returns the image that was assigned to a specific segment. /// Will return nil if the content at that segment is not an image. @@ -122,7 +125,8 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// /// @param title The text to display at the segment. /// @param index The index of the segment to set. -- (void)setTitle:(NSString *)title forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:forSegmentAt:)); +- (void)setTitle:(NSString *)title + forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:forSegmentAt:)); /// Sets the content of a given segment to a text label, and /// optionally makes it reversible. @@ -130,8 +134,9 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// @param title The text to display at the segment. /// @param reversible Whether the item can be tapped multiple times to flip directions. /// @param index The index of the segment to set. -- (void)setTitle:(NSString *)title reversible:(BOOL)reversible - forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:reversible:forSegmentAt:)); +- (void)setTitle:(NSString *)title + reversible:(BOOL)reversible + forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(set(_:reversible:forSegmentAt:)); /// Returns the string of the title that was assigned to a specific segment. /// Will return nil if the content at that segment is not a string. @@ -145,10 +150,11 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl - (void)addSegmentWithTitle:(NSString *)title NS_SWIFT_NAME(addSegment(withTitle:)); /// Adds a new text segment to the end of the list, and optionally makes it reversible. -/// +/// /// @param title The title of the new item. /// @param reversible Whether the item is reversible or not. -- (void)addSegmentWithTitle:(NSString *)title reversible:(BOOL)reversible NS_SWIFT_NAME(addSegment(withTitle:reversible:)); +- (void)addSegmentWithTitle:(NSString *)title + reversible:(BOOL)reversible NS_SWIFT_NAME(addSegment(withTitle:reversible:)); /// Adds a new image segment to the end of the list. /// @@ -159,13 +165,15 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// /// @param image The image of the new item. /// @param reversible Whether the item is reversible or not. -- (void)addSegmentWithImage:(UIImage *)image reversible:(BOOL)reversible NS_SWIFT_NAME(addSegment(with:reversible:)); +- (void)addSegmentWithImage:(UIImage *)image + reversible:(BOOL)reversible NS_SWIFT_NAME(addSegment(with:reversible:)); /// Inserts a new image segment at the specified index. /// /// @param image The image to set. /// @param index The index of the segment to which the image will be set. -- (void)insertSegmentWithImage:(UIImage *)image atIndex:(NSInteger)index NS_SWIFT_NAME(insertSegment(with:at:)); +- (void)insertSegmentWithImage:(UIImage *)image + atIndex:(NSInteger)index NS_SWIFT_NAME(insertSegment(with:at:)); /** Inserts a new image segment at the specified segment index, and optionally makes it reversible. @@ -174,22 +182,26 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl @param reversible Whether the item is reversible or not. @param index The index of the segment to which the image will be set. */ -- (void)insertSegmentWithImage:(UIImage *)image reversible:(BOOL)reversible - atIndex:(NSInteger)index NS_SWIFT_NAME(insertSegment(with:reversible:at:)); +- (void)insertSegmentWithImage:(UIImage *)image + reversible:(BOOL)reversible + atIndex:(NSInteger)index NS_SWIFT_NAME(insertSegment(with:reversible:at:)); /// Inserts a new title segment at the specified index. /// /// @param title The title to set. /// @param index The index of the segment to which the image will be set. -- (void)insertSegmentWithTitle:(NSString *)title atIndex:(NSInteger)index NS_SWIFT_NAME(insertSegment(withTitle:at:)); +- (void)insertSegmentWithTitle:(NSString *)title + atIndex:(NSInteger)index NS_SWIFT_NAME(insertSegment(withTitle:at:)); /// Inserts a new title segment at the specified index, and optionally makes it reversible. /// /// @param title The title to set. /// @param reversible Whether the item is reversible or not. /// @param index The index of the segment to which the image will be set. -- (void)insertSegmentWithTitle:(NSString *)title reversible:(BOOL)reversible - atIndex:(NSInteger)index NS_SWIFT_NAME(insertSegment(withTitle:reversible:at:)); +- (void)insertSegmentWithTitle:(NSString *)title + reversible:(BOOL)reversible + atIndex:(NSInteger)index + NS_SWIFT_NAME(insertSegment(withTitle:reversible:at:)); /// Remove the last segment in the list - (void)removeLastSegment NS_SWIFT_NAME(removeLastSegment()); @@ -206,7 +218,8 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// /// @param enabled Whether the segment is enabled or not. /// @param index The specific index to enable/disable. -- (void)setEnabled:(BOOL)enabled forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(setEnabled(_:forSegmentAt:)); +- (void)setEnabled:(BOOL)enabled + forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(setEnabled(_:forSegmentAt:)); /// Returns whether the segment at the specified index is currently enabled or not. /// @@ -217,7 +230,8 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// /// @param reversible Whether the segment is reversible or not. /// @param index The specific index to enable/disable. -- (void)setReversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(setReversible(_:forSegmentAt:)); +- (void)setReversible:(BOOL)reversible + forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(setReversible(_:forSegmentAt:)); /// Returns whether the segment at the specified index is reversible or not. /// @@ -228,18 +242,21 @@ IB_DESIGNABLE @interface TOSegmentedControl : UIControl /// /// @param reversed Whether the segment is currently reversed or not. /// @param index The specific index to enable/disable. -- (void)setReversed:(BOOL)reversed forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(setReversed(_:forSegmentAt:)); +- (void)setReversed:(BOOL)reversed + forSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(setReversed(_:forSegmentAt:)); /// Returns whether the segment at the specified index is currently reversed or not. /// /// @param index The index to check. - (BOOL)isReversedForSegmentAtIndex:(NSInteger)index NS_SWIFT_NAME(isReversed(at:)); -/// Sets which segment is currently selected, and optionally play an animation during the transition. +/// Sets which segment is currently selected, and optionally play an animation during the +/// transition. /// /// @param selectedSegmentIndex The index of the segment to select. /// @param animated Whether the transition to the newly selected index is animated or not. -- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex animated:(BOOL)animated NS_SWIFT_NAME(setSelectedSegmentIndex(_:animated:)); +- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex + animated:(BOOL)animated NS_SWIFT_NAME(setSelectedSegmentIndex(_:animated:)); @end diff --git a/TOSegmentedControl/TOSegmentedControl.m b/TOSegmentedControl/TOSegmentedControl.m index 517e166..c7ca858 100644 --- a/TOSegmentedControl/TOSegmentedControl.m +++ b/TOSegmentedControl/TOSegmentedControl.m @@ -21,6 +21,7 @@ // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #import "TOSegmentedControl.h" + #import "TOSegmentedControlSegment.h" // ---------------------------------------------------------------- @@ -36,8 +37,8 @@ // Internal Members // Statically referenced key names for the images stored in the map table. -static NSString * const kTOSegmentedControlArrowImage = @"arrowIcon"; -static NSString * const kTOSegmentedControlSeparatorImage = @"separatorImage"; +static NSString *const kTOSegmentedControlArrowImage = @"arrowIcon"; +static NSString *const kTOSegmentedControlSeparatorImage = @"separatorImage"; // When tapped the amount the focused elements will shrink / fade static CGFloat const kTOSegmentedControlSelectedTextAlpha = 0.3f; @@ -99,8 +100,7 @@ @implementation TOSegmentedControl #pragma mark - Class Init - -- (instancetype)initWithItems:(NSArray *)items -{ +- (instancetype)initWithItems:(NSArray *)items { if (self = [super initWithFrame:(CGRect){0.0f, 0.0f, 300.0f, 32.0f}]) { [self commonInit]; self.items = [self sanitizedItemArrayWithItems:items]; @@ -109,8 +109,7 @@ - (instancetype)initWithItems:(NSArray *)items return self; } -- (instancetype)initWithCoder:(NSCoder *)coder -{ +- (instancetype)initWithCoder:(NSCoder *)coder { if (self = [super initWithCoder:coder]) { [self commonInit]; } @@ -118,8 +117,7 @@ - (instancetype)initWithCoder:(NSCoder *)coder return self; } -- (instancetype)initWithFrame:(CGRect)frame -{ +- (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self commonInit]; } @@ -127,8 +125,7 @@ - (instancetype)initWithFrame:(CGRect)frame return self; } -- (instancetype)init -{ +- (instancetype)init { if (self = [super initWithFrame:(CGRect){0.0f, 0.0f, 300.0f, 32.0f}]) { [self commonInit]; } @@ -136,32 +133,36 @@ - (instancetype)init return self; } -- (void)commonInit -{ +- (void)commonInit { // Create content view self.trackView = [[UIView alloc] initWithFrame:self.bounds]; - self.trackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.trackView.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.trackView.layer.masksToBounds = YES; self.trackView.userInteractionEnabled = NO; - #ifdef __IPHONE_13_0 - if (@available(iOS 13.0, *)) { self.trackView.layer.cornerCurve = kCACornerCurveContinuous; } - #endif +#ifdef __IPHONE_13_0 + if (@available(iOS 13.0, *)) { + self.trackView.layer.cornerCurve = kCACornerCurveContinuous; + } +#endif [self addSubview:self.trackView]; // Create thumb view self.thumbView = [[UIView alloc] initWithFrame:CGRectMake(2.0f, 2.0f, 100.0f, 28.0f)]; self.thumbView.layer.shadowColor = [UIColor blackColor].CGColor; - #ifdef __IPHONE_13_0 - if (@available(iOS 13.0, *)) { self.thumbView.layer.cornerCurve = kCACornerCurveContinuous; } - #endif +#ifdef __IPHONE_13_0 + if (@available(iOS 13.0, *)) { + self.thumbView.layer.cornerCurve = kCACornerCurveContinuous; + } +#endif [self.trackView addSubview:self.thumbView]; // Create list for managing each item self.segments = [NSMutableArray array]; - + // Create containers for views self.separatorViews = [NSMutableArray array]; - + // Set default resettable values self.backgroundColor = nil; self.thumbColor = nil; @@ -196,34 +197,34 @@ - (void)commonInit // Configure view interaction // When the user taps down in the view [self addTarget:self - action:@selector(didTapDown:withEvent:) - forControlEvents:UIControlEventTouchDown]; - + action:@selector(didTapDown:withEvent:) + forControlEvents:UIControlEventTouchDown]; + // When the user drags, either inside or out of the view [self addTarget:self - action:@selector(didDragTap:withEvent:) - forControlEvents:UIControlEventTouchDragInside|UIControlEventTouchDragOutside]; - + action:@selector(didDragTap:withEvent:) + forControlEvents:UIControlEventTouchDragInside | UIControlEventTouchDragOutside]; + // When the user's finger leaves the bounds of the view [self addTarget:self - action:@selector(didExitTapBounds:withEvent:) - forControlEvents:UIControlEventTouchDragExit]; - + action:@selector(didExitTapBounds:withEvent:) + forControlEvents:UIControlEventTouchDragExit]; + // When the user's finger re-enters the bounds [self addTarget:self - action:@selector(didEnterTapBounds:withEvent:) - forControlEvents:UIControlEventTouchDragEnter]; - + action:@selector(didEnterTapBounds:withEvent:) + forControlEvents:UIControlEventTouchDragEnter]; + // When the user taps up, either inside or out [self addTarget:self - action:@selector(didEndTap:withEvent:) - forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside|UIControlEventTouchCancel]; + action:@selector(didEndTap:withEvent:) + forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside | + UIControlEventTouchCancel]; } #pragma mark - Item Management - -- (NSMutableArray *)sanitizedItemArrayWithItems:(NSArray *)items -{ +- (NSMutableArray *)sanitizedItemArrayWithItems:(NSArray *)items { // Filter the items to extract only strings and images NSMutableArray *sanitizedItems = [NSMutableArray array]; for (id item in items) { @@ -236,8 +237,7 @@ - (NSMutableArray *)sanitizedItemArrayWithItems:(NSArray *)items return sanitizedItems; } -- (void)updateSeparatorViewCount -{ +- (void)updateSeparatorViewCount { // Work out how many separators we need (One less than segments) NSInteger numberOfSeparators = self.segments.count - 1; @@ -262,89 +262,93 @@ - (void)updateSeparatorViewCount #pragma mark - Public Item Access - -- (nullable UIImage *)imageForSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.segments.count) { return nil; } +- (nullable UIImage *)imageForSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.segments.count) { + return nil; + } return [self objectForSegmentAtIndex:index class:UIImage.class]; } -- (nullable NSString *)titleForSegmentAtIndex:(NSInteger)index -{ +- (nullable NSString *)titleForSegmentAtIndex:(NSInteger)index { return [self objectForSegmentAtIndex:index class:NSString.class]; } -- (nullable id)objectForSegmentAtIndex:(NSInteger)index class:(Class)class -{ +- (nullable id)objectForSegmentAtIndex:(NSInteger)index class:(Class)class { // Make sure the index provided is valid - if (index < 0 || index >= self.items.count) { return nil; } + if (index < 0 || index >= self.items.count) { + return nil; + } // Return the item only if it is an image id item = self.items[index]; - if ([item isKindOfClass:class]) { return item; } - + if ([item isKindOfClass:class]) { + return item; + } + // Return nil if a label or anything else return nil; } #pragma mark Add New Items -- (void)addSegmentWithImage:(UIImage *)image -{ +- (void)addSegmentWithImage:(UIImage *)image { [self addSegmentWithImage:image reversible:NO]; } -- (void)addSegmentWithImage:(UIImage *)image reversible:(BOOL)reversible -{ +- (void)addSegmentWithImage:(UIImage *)image reversible:(BOOL)reversible { [self addSegmentWithObject:image reversible:reversible]; } -- (void)addSegmentWithTitle:(NSString *)title -{ +- (void)addSegmentWithTitle:(NSString *)title { [self addSegmentWithTitle:title reversible:NO]; } -- (void)addSegmentWithTitle:(NSString *)title reversible:(BOOL)reversible -{ +- (void)addSegmentWithTitle:(NSString *)title reversible:(BOOL)reversible { [self addSegmentWithObject:title reversible:reversible]; } -- (void)addSegmentWithObject:(id)object reversible:(BOOL)reversible -{ +- (void)addSegmentWithObject:(id)object reversible:(BOOL)reversible { [self insertSegmentWithObject:object reversible:reversible atIndex:self.segments.count]; } #pragma mark Inserting New Items -- (void)insertSegmentWithTitle:(NSString *)title atIndex:(NSInteger)index -{ +- (void)insertSegmentWithTitle:(NSString *)title atIndex:(NSInteger)index { [self insertSegmentWithTitle:title reversible:NO atIndex:index]; } -- (void)insertSegmentWithTitle:(NSString *)title reversible:(BOOL)reversible atIndex:(NSInteger)index -{ +- (void)insertSegmentWithTitle:(NSString *)title + reversible:(BOOL)reversible + atIndex:(NSInteger)index { [self insertSegmentWithObject:title reversible:reversible atIndex:index]; } -- (void)insertSegmentWithImage:(UIImage *)image atIndex:(NSInteger)index -{ +- (void)insertSegmentWithImage:(UIImage *)image atIndex:(NSInteger)index { [self insertSegmentWithImage:image reversible:NO atIndex:index]; } -- (void)insertSegmentWithImage:(UIImage *)image reversible:(BOOL)reversible atIndex:(NSInteger)index -{ +- (void)insertSegmentWithImage:(UIImage *)image + reversible:(BOOL)reversible + atIndex:(NSInteger)index { [self insertSegmentWithObject:image reversible:reversible atIndex:index]; } -- (void)insertSegmentWithObject:(id)object reversible:(BOOL)reversible atIndex:(NSInteger)index -{ +- (void)insertSegmentWithObject:(id)object reversible:(BOOL)reversible atIndex:(NSInteger)index { // If an invalid index was provided, cap it to the available range - if (index < 0) { index = 0; } - if (index >= self.segments.count) { index = self.segments.count; } + if (index < 0) { + index = 0; + } + if (index >= self.segments.count) { + index = self.segments.count; + } // Add item to master list (Create a new list if one didn't exist) NSMutableArray *items = nil; - if (self.items) { items = [self.items mutableCopy]; } - else { items = [NSMutableArray array]; } + if (self.items) { + items = [self.items mutableCopy]; + } else { + items = [NSMutableArray array]; + } [items insertObject:object atIndex:index]; _items = [NSArray arrayWithArray:items]; @@ -363,60 +367,61 @@ - (void)insertSegmentWithObject:(id)object reversible:(BOOL)reversible atIndex:( #pragma mark Replacing Items -- (void)setImage:(UIImage *)image forSegmentAtIndex:(NSInteger)index -{ +- (void)setImage:(UIImage *)image forSegmentAtIndex:(NSInteger)index { [self setImage:image reversible:NO forSegmentAtIndex:index]; } -- (void)setImage:(UIImage *)image reversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index -{ +- (void)setImage:(UIImage *)image reversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index { [self setObject:image reversible:reversible forSegmentAtIndex:index]; } -- (void)setTitle:(NSString *)title forSegmentAtIndex:(NSInteger)index -{ +- (void)setTitle:(NSString *)title forSegmentAtIndex:(NSInteger)index { [self setTitle:title reversible:NO forSegmentAtIndex:index]; } -- (void)setTitle:(NSString *)title reversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index -{ +- (void)setTitle:(NSString *)title reversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index { [self setObject:title reversible:reversible forSegmentAtIndex:index]; } -- (void)setObject:(id)object reversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index -{ +- (void)setObject:(id)object reversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index { NSAssert([object isKindOfClass:NSString.class] || [object isKindOfClass:UIImage.class], - @"TOSegmentedControl: Only images and strings are supported."); - + @"TOSegmentedControl: Only images and strings are supported."); + // Make sure we don't go out of bounds - if (index < 0 || index >= self.items.count) { return; } - + if (index < 0 || index >= self.items.count) { + return; + } + // Remove the item from the item list and insert the new one NSMutableArray *items = [self.items mutableCopy]; [items removeObjectAtIndex:index]; [items insertObject:object atIndex:index]; _items = [NSArray arrayWithArray:items]; - + // Update the item object at that point for the new item TOSegmentedControlSegment *segment = self.segments[index]; - if ([object isKindOfClass:NSString.class]) { segment.title = object; } - if ([object isKindOfClass:UIImage.class]) { segment.image = object; } + if ([object isKindOfClass:NSString.class]) { + segment.title = object; + } + if ([object isKindOfClass:UIImage.class]) { + segment.image = object; + } segment.isReversible = reversible; - + // Re-layout the views [self setNeedsLayout]; } #pragma mark Deleting Items -- (void)removeLastSegment -{ +- (void)removeLastSegment { [self removeSegmentAtIndex:self.items.count - 1]; } -- (void)removeSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.items.count) { return; } +- (void)removeSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.items.count) { + return; + } // Remove from the item list NSMutableArray *items = self.items.mutableCopy; @@ -431,10 +436,9 @@ - (void)removeSegmentAtIndex:(NSInteger)index [self updateSeparatorViewCount]; } -- (void)removeAllSegments -{ +- (void)removeAllSegments { // Remove all item objects - for (TOSegmentedControlSegment * segment in self.segments) { + for (TOSegmentedControlSegment *segment in self.segments) { [segment.containerView removeFromSuperview]; } self.segments = [NSMutableArray array]; @@ -451,9 +455,10 @@ - (void)removeAllSegments #pragma mark Enabled/Disabled -- (void)setEnabled:(BOOL)enabled forSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.segments.count) { return; } +- (void)setEnabled:(BOOL)enabled forSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.segments.count) { + return; + } self.segments[index].isDisabled = !enabled; [self setNeedsLayout]; @@ -464,14 +469,18 @@ - (void)setEnabled:(BOOL)enabled forSegmentAtIndex:(NSInteger)index // Loop ahead of the selected segment index to find the next enabled one for (NSInteger i = self.selectedSegmentIndex; i < self.segments.count; i++) { - if (self.segments[i].isDisabled) { continue; } + if (self.segments[i].isDisabled) { + continue; + } self.selectedSegmentIndex = i; return; } // If that failed, loop forward to find an enabled one before it for (NSInteger i = self.selectedSegmentIndex; i >= 0; i--) { - if (self.segments[i].isDisabled) { continue; } + if (self.segments[i].isDisabled) { + continue; + } self.selectedSegmentIndex = i; return; } @@ -480,9 +489,10 @@ - (void)setEnabled:(BOOL)enabled forSegmentAtIndex:(NSInteger)index self.selectedSegmentIndex = -1; } -- (BOOL)isEnabledForSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.segments.count) { return NO; } +- (BOOL)isEnabledForSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.segments.count) { + return NO; + } return !self.segments[index].isDisabled; } @@ -490,35 +500,38 @@ - (BOOL)isEnabledForSegmentAtIndex:(NSInteger)index // Accessors for setting when a segment is reversible. -- (void)setReversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.segments.count) { return; } +- (void)setReversible:(BOOL)reversible forSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.segments.count) { + return; + } self.segments[index].isReversible = reversible; } -- (BOOL)isReversibleForSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.segments.count) { return NO; } +- (BOOL)isReversibleForSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.segments.count) { + return NO; + } return !self.segments[index].isReversible; } // Accessors for toggling whether a reversible segment is currently reversed. -- (void)setReversed:(BOOL)reversed forSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.segments.count) { return; } +- (void)setReversed:(BOOL)reversed forSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.segments.count) { + return; + } self.segments[index].isReversed = reversed; } -- (BOOL)isReversedForSegmentAtIndex:(NSInteger)index -{ - if (index < 0 || index >= self.segments.count) { return NO; } +- (BOOL)isReversedForSegmentAtIndex:(NSInteger)index { + if (index < 0 || index >= self.segments.count) { + return NO; + } return !self.segments[index].isReversed; } #pragma mark - View Layout - -- (void)layoutThumbView -{ +- (void)layoutThumbView { // Hide the thumb view if no segments are selected if (self.selectedSegmentIndex < 0 || !self.enabled) { self.thumbView.hidden = YES; @@ -532,8 +545,9 @@ - (void)layoutThumbView // Match the shadow path to the new size of the thumb view CGPathRef oldShadowPath = self.thumbView.layer.shadowPath; - UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, frame.size} - cornerRadius:[self _cornerRadiusValue] - self.thumbInset]; + UIBezierPath *shadowPath = + [UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, frame.size} + cornerRadius:[self _cornerRadiusValue] - self.thumbInset]; // If the segmented control is animating its shape, to prevent the // shadow from visibly snapping, perform a resize animation on it @@ -549,8 +563,7 @@ - (void)layoutThumbView self.thumbView.layer.shadowPath = shadowPath.CGPath; } -- (void)layoutItemViews -{ +- (void)layoutItemViews { // Lay out the item views NSInteger i = 0; for (TOSegmentedControlSegment *item in self.segments) { @@ -564,21 +577,22 @@ - (void)layoutItemViews // Work out the appropriate size of the item CGRect itemFrame = itemView.frame; - + // Cap its size to be within the segmented frame itemFrame.size.height = MIN(thumbFrame.size.height, itemFrame.size.height); itemFrame.size.width = MIN(thumbFrame.size.width, itemFrame.size.width); - + // If the item is reversible, make sure there is also room to show the arrow - CGFloat arrowSpacing = (self.arrowImage.size.width + kTOSegmentedControlDirectionArrowMargin) * 2.0f; + CGFloat arrowSpacing = + (self.arrowImage.size.width + kTOSegmentedControlDirectionArrowMargin) * 2.0f; if (item.isReversible && (itemFrame.size.width + arrowSpacing) > thumbFrame.size.width) { itemFrame.size.width -= arrowSpacing; } - + // Center the item in the container itemFrame.origin.x = (CGRectGetWidth(thumbFrame) - itemFrame.size.width) * 0.5f; itemFrame.origin.y = (CGRectGetHeight(thumbFrame) - itemFrame.size.height) * 0.5f; - + // Set the item frame itemView.frame = CGRectIntegral(itemFrame); @@ -594,14 +608,15 @@ - (void)layoutItemViews } // Exit out if there is nothing selected - if (self.selectedSegmentIndex < 0) { return; } + if (self.selectedSegmentIndex < 0) { + return; + } // Set the selected state for the current selected index [self setItemAtIndex:self.selectedSegmentIndex selected:YES]; } -- (void)layoutSeparatorViews -{ +- (void)layoutSeparatorViews { CGSize size = self.trackView.frame.size; CGFloat segmentWidth = self.segmentWidth; CGFloat xOffset = (_thumbInset + segmentWidth) - 1.0f; @@ -616,12 +631,11 @@ - (void)layoutSeparatorViews i++; } - // Update the alpha of the separator views - [self refreshSeparatorViewsForSelectedIndex:self.selectedSegmentIndex]; + // Update the alpha of the separator views + [self refreshSeparatorViewsForSelectedIndex:self.selectedSegmentIndex]; } -- (void)layoutSubviews -{ +- (void)layoutSubviews { [super layoutSubviews]; // Lay-out the thumb view @@ -634,30 +648,27 @@ - (void)layoutSubviews [self layoutSeparatorViews]; } -- (CGFloat)segmentWidth -{ +- (CGFloat)segmentWidth { return floorf((self.bounds.size.width - (_thumbInset * 2.0f)) / self.numberOfSegments); } -- (CGRect)frameForSegmentAtIndex:(NSInteger)index -{ +- (CGRect)frameForSegmentAtIndex:(NSInteger)index { CGSize size = self.trackView.frame.size; - + CGRect frame = CGRectZero; frame.origin.x = _thumbInset + (self.segmentWidth * index) + ((_thumbInset * 2.0f) * index); frame.origin.y = _thumbInset; frame.size.width = self.segmentWidth; frame.size.height = size.height - (_thumbInset * 2.0f); - + // Cap the position of the frame so it won't overshoot frame.origin.x = MAX(_thumbInset, frame.origin.x); frame.origin.x = MIN(size.width - (self.segmentWidth + _thumbInset), frame.origin.x); - + return CGRectIntegral(frame); } -- (CGRect)frameForImageArrowViewWithItemFrame:(CGRect)itemFrame -{ +- (CGRect)frameForImageArrowViewWithItemFrame:(CGRect)itemFrame { CGRect frame = CGRectZero; frame.size = self.arrowImage.size; frame.origin.x = CGRectGetMaxX(itemFrame) + kTOSegmentedControlDirectionArrowMargin; @@ -665,24 +676,20 @@ - (CGRect)frameForImageArrowViewWithItemFrame:(CGRect)itemFrame return frame; } -- (NSInteger)segmentIndexForPoint:(CGPoint)point -{ +- (NSInteger)segmentIndexForPoint:(CGPoint)point { CGFloat segmentWidth = floorf(self.frame.size.width / self.numberOfSegments); NSInteger segment = floorf(point.x / segmentWidth); segment = MAX(segment, 0); - segment = MIN(segment, self.numberOfSegments-1); + segment = MIN(segment, self.numberOfSegments - 1); return segment; } -- (void)setThumbViewShrunken:(BOOL)shrunken -{ +- (void)setThumbViewShrunken:(BOOL)shrunken { CGFloat scale = shrunken ? kTOSegmentedControlSelectedScale : 1.0f; - self.thumbView.transform = CGAffineTransformScale(CGAffineTransformIdentity, - scale, scale); + self.thumbView.transform = CGAffineTransformScale(CGAffineTransformIdentity, scale, scale); } -- (void)setItemViewAtIndex:(NSInteger)segmentIndex shrunken:(BOOL)shrunken -{ +- (void)setItemViewAtIndex:(NSInteger)segmentIndex shrunken:(BOOL)shrunken { NSAssert(segmentIndex >= 0 && segmentIndex < self.items.count, @"TOSegmentedControl: Array should not be out of bounds"); @@ -693,17 +700,17 @@ - (void)setItemViewAtIndex:(NSInteger)segmentIndex shrunken:(BOOL)shrunken if (shrunken == NO) { itemView.transform = CGAffineTransformIdentity; - } - else { + } else { CGFloat scale = kTOSegmentedControlSelectedScale; - itemView.transform = CGAffineTransformScale(CGAffineTransformIdentity, - scale, scale); + itemView.transform = CGAffineTransformScale(CGAffineTransformIdentity, scale, scale); } // If we have a reversible image view, manipulate its transformation // to match the position and scale of the item view UIView *arrowView = segment.arrowView; - if (arrowView == nil) { return; } + if (arrowView == nil) { + return; + } if (!shrunken) { arrowView.transform = CGAffineTransformIdentity; @@ -727,8 +734,7 @@ - (void)setItemViewAtIndex:(NSInteger)segmentIndex shrunken:(BOOL)shrunken arrowView.transform = transform; } -- (void)setItemViewAtIndex:(NSInteger)segmentIndex reversed:(BOOL)reversed -{ +- (void)setItemViewAtIndex:(NSInteger)segmentIndex reversed:(BOOL)reversed { NSAssert(segmentIndex >= 0 && segmentIndex < self.items.count, @"TOSegmentedControl: Array should not be out of bounds"); @@ -736,8 +742,7 @@ - (void)setItemViewAtIndex:(NSInteger)segmentIndex reversed:(BOOL)reversed [segment setArrowImageReversed:reversed]; } -- (void)setItemAtIndex:(NSInteger)index selected:(BOOL)selected -{ +- (void)setItemAtIndex:(NSInteger)index selected:(BOOL)selected { NSAssert(index >= 0 && index < self.segments.count, @"TOSegmentedControl: Array should not be out of bounds"); @@ -750,7 +755,9 @@ - (void)setItemAtIndex:(NSInteger)index selected:(BOOL)selected // The rest of this code deals with swapping the font // of the label. Cancel out if we're an image. UILabel *label = segment.label; - if (label == nil) { return; } + if (label == nil) { + return; + } // Set the font UIFont *font = selected ? self.selectedTextFont : self.textFont; @@ -758,10 +765,10 @@ - (void)setItemAtIndex:(NSInteger)index selected:(BOOL)selected // Set the text color label.textColor = selected ? self.selectedItemColor : self.itemColor; - + // Set the arrow tint color segment.arrowView.tintColor = label.textColor; - + // Re-apply the arrow image view to the translated frame segment.arrowView.frame = [self frameForImageArrowViewWithItemFrame:label.frame]; @@ -769,21 +776,17 @@ - (void)setItemAtIndex:(NSInteger)index selected:(BOOL)selected [segment setArrowImageReversed:segment.isReversed]; } -- (void)setItemAtIndex:(NSInteger)index faded:(BOOL)faded -{ - NSAssert(index >= 0 && index < self.segments.count, - @"Array should not be out of bounds"); +- (void)setItemAtIndex:(NSInteger)index faded:(BOOL)faded { + NSAssert(index >= 0 && index < self.segments.count, @"Array should not be out of bounds"); UIView *itemView = self.segments[index].itemView; itemView.alpha = faded ? kTOSegmentedControlSelectedTextAlpha : 1.0f; } -- (void)refreshSeparatorViewsForSelectedIndex:(NSInteger)index -{ +- (void)refreshSeparatorViewsForSelectedIndex:(NSInteger)index { [self refreshSeparatorViewsForSelectedIndexes:[NSSet setWithObject:@(index)]]; } -- (void)refreshSeparatorViewsForSelectedIndexes:(NSSet *)indexes -{ +- (void)refreshSeparatorViewsForSelectedIndexes:(NSSet *)indexes { // Hide the separators on either side of the selected segment NSInteger i = 0; for (UIView *separatorView in self.separatorViews) { @@ -794,7 +797,7 @@ - (void)refreshSeparatorViewsForSelectedIndexes:(NSSet *)indexes } // Hide the index (right side) and the previous index (left side) if it's in the set - BOOL containsIndex = ([indexes containsObject:@(i)] || [indexes containsObject:@(i+1)]); + BOOL containsIndex = ([indexes containsObject:@(i)] || [indexes containsObject:@(i + 1)]); separatorView.alpha = containsIndex ? 0.0f : 1.0f; i++; } @@ -802,10 +805,11 @@ - (void)refreshSeparatorViewsForSelectedIndexes:(NSSet *)indexes #pragma mark - Touch Interaction - -- (void)didTapDown:(UIControl *)control withEvent:(UIEvent *)event -{ +- (void)didTapDown:(UIControl *)control withEvent:(UIEvent *)event { // Exit out if the control is disabled - if (!self.enabled || self.hasNoSegments) { return; } + if (!self.enabled || self.hasNoSegments) { + return; + } // Determine which segment the user tapped CGPoint tapPoint = [event.allTouches.anyObject locationInView:self]; @@ -815,7 +819,7 @@ - (void)didTapDown:(UIControl *)control withEvent:(UIEvent *)event if (self.segments[tappedIndex].isDisabled) { return; } - + // Work out if we tapped on the thumb view, or on an un-selected segment self.isDraggingThumbView = (tappedIndex == self.selectedSegmentIndex); @@ -832,19 +836,18 @@ - (void)didTapDown:(UIControl *)control withEvent:(UIEvent *)event // Work out which animation effects to apply if (!self.isDraggingThumbView) { - [UIView animateWithDuration:0.35f animations:^{ - [self setItemAtIndex:tappedIndex faded:YES]; - }]; - + [UIView animateWithDuration:0.35f + animations:^{ [self setItemAtIndex:tappedIndex faded:YES]; }]; + [self setSelectedSegmentIndex:tappedIndex animated:YES]; return; } - + id animationBlock = ^{ [self setThumbViewShrunken:YES]; [self setItemViewAtIndex:self.selectedSegmentIndex shrunken:YES]; }; - + // Animate the transition [UIView animateWithDuration:0.3f delay:0.0f @@ -855,10 +858,11 @@ - (void)didTapDown:(UIControl *)control withEvent:(UIEvent *)event completion:nil]; } -- (void)didDragTap:(UIControl *)control withEvent:(UIEvent *)event -{ +- (void)didDragTap:(UIControl *)control withEvent:(UIEvent *)event { // Exit out if the control is disabled - if (!self.enabled || self.hasNoSegments) { return; } + if (!self.enabled || self.hasNoSegments) { + return; + } CGPoint tapPoint = [event.allTouches.anyObject locationInView:self]; NSInteger tappedIndex = [self segmentIndexForPoint:tapPoint]; @@ -869,7 +873,7 @@ - (void)didDragTap:(UIControl *)control withEvent:(UIEvent *)event } if (tappedIndex == self.focusedIndex) { - return; + return; } // If the control or item is disabled, pass @@ -883,52 +887,54 @@ - (void)didDragTap:(UIControl *)control withEvent:(UIEvent *)event // Handle transitioning when not dragging the thumb view if (!self.isDraggingThumbView) { // If we dragged out of the bounds, disregard - if (self.focusedIndex < 0) { return; } - + if (self.focusedIndex < 0) { + return; + } + id animationBlock = ^{ // Deselect the current item [self setItemAtIndex:self.focusedIndex faded:NO]; - + // Fade the text if it is NOT the thumb track one if (tappedIndex != self.selectedSegmentIndex) { [self setItemAtIndex:tappedIndex faded:YES]; } }; - + // Perform a faster change over animation [UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:animationBlock completion:nil]; - + // Update the focused item self.focusedIndex = tappedIndex; return; } - + // Get the new frame of the segment CGRect frame = [self frameForSegmentAtIndex:tappedIndex]; - + // Work out the center point from the frame CGPoint center = (CGPoint){CGRectGetMidX(frame), CGRectGetMidY(frame)}; // Create the animation block id animationBlock = ^{ self.thumbView.center = center; - + // Deselect the focused item [self setItemAtIndex:self.focusedIndex selected:NO]; [self setItemViewAtIndex:self.focusedIndex shrunken:NO]; - + // Select the new one [self setItemAtIndex:tappedIndex selected:YES]; [self setItemViewAtIndex:tappedIndex shrunken:YES]; - + // Update the separators [self refreshSeparatorViewsForSelectedIndex:tappedIndex]; }; - + // Perform the animation [UIView animateWithDuration:0.45 delay:0.0f @@ -937,41 +943,47 @@ - (void)didDragTap:(UIControl *)control withEvent:(UIEvent *)event options:UIViewAnimationOptionBeginFromCurrentState animations:animationBlock completion:nil]; - + // Update the focused item self.focusedIndex = tappedIndex; } -- (void)didExitTapBounds:(UIControl *)control withEvent:(UIEvent *)event -{ +- (void)didExitTapBounds:(UIControl *)control withEvent:(UIEvent *)event { // Exit out if the control is disabled - if (!self.enabled || self.hasNoSegments) { return; } + if (!self.enabled || self.hasNoSegments) { + return; + } // No effects needed when tracking the thumb view - if (self.isDraggingThumbView) { return; } - + if (self.isDraggingThumbView) { + return; + } + // Un-fade the focused item [UIView animateWithDuration:0.45f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^{ [self setItemAtIndex:self.focusedIndex faded:NO]; } completion:nil]; - + // Disable the focused index self.focusedIndex = -1; } -- (void)didEnterTapBounds:(UIControl *)control withEvent:(UIEvent *)event -{ +- (void)didEnterTapBounds:(UIControl *)control withEvent:(UIEvent *)event { // Exit out if the control is disabled - if (!self.enabled || self.hasNoSegments) { return; } + if (!self.enabled || self.hasNoSegments) { + return; + } // No effects needed when tracking the thumb view - if (self.isDraggingThumbView) { return; } - + if (self.isDraggingThumbView) { + return; + } + CGPoint tapPoint = [event.allTouches.anyObject locationInView:self]; self.focusedIndex = [self segmentIndexForPoint:tapPoint]; - + // Un-fade the focused item [UIView animateWithDuration:0.45f delay:0.0f @@ -980,10 +992,11 @@ - (void)didEnterTapBounds:(UIControl *)control withEvent:(UIEvent *)event completion:nil]; } -- (void)didEndTap:(UIControl *)control withEvent:(UIEvent *)event -{ +- (void)didEndTap:(UIControl *)control withEvent:(UIEvent *)event { // Exit out if the control is disabled - if (!self.enabled || self.hasNoSegments) { return; } + if (!self.enabled || self.hasNoSegments) { + return; + } // Capture the touch object in order to track its state UITouch *touch = event.allTouches.anyObject; @@ -999,13 +1012,14 @@ - (void)didEndTap:(UIControl *)control withEvent:(UIEvent *)event // If we WEREN'T dragging the thumb view, work out where we need to move to if (!self.isDraggingThumbView) { - if (segment.isDisabled) { return; } + if (segment.isDisabled) { + return; + } // If we weren't cancelled, animate to the new index if (!isCancelled) { [self setSelectedSegmentIndex:tappedIndex animated:YES]; - } - else { + } else { // Else, reset the currently highlighted item [self didExitTapBounds:self withEvent:event]; } @@ -1025,8 +1039,7 @@ - (void)didEndTap:(UIControl *)control withEvent:(UIEvent *)event if (self.selectedSegmentIndex != tappedIndex) { _selectedSegmentIndex = tappedIndex; [self sendIndexChangedEventActions]; - } - else if (segment.isReversible && !self.didDragOffOriginalSegment) { + } else if (segment.isReversible && !self.didDragOffOriginalSegment) { // If the item was reversible, and we never changed segments, // trigger the reverse alert delegate [segment toggleDirection]; @@ -1042,32 +1055,29 @@ - (void)didEndTap:(UIControl *)control withEvent:(UIEvent *)event id animationBlock = ^{ [self setThumbViewShrunken:NO]; [self setItemViewAtIndex:self.selectedSegmentIndex shrunken:NO]; - [self setItemViewAtIndex:self.selectedSegmentIndex - reversed:self.selectedSegmentReversed]; + [self setItemViewAtIndex:self.selectedSegmentIndex reversed:self.selectedSegmentReversed]; }; // Animate the transition [UIView animateWithDuration:0.3f - delay:0.0f - usingSpringWithDamping:1.0f - initialSpringVelocity:0.1f - options:UIViewAnimationOptionBeginFromCurrentState - animations:animationBlock - completion:nil]; + delay:0.0f + usingSpringWithDamping:1.0f + initialSpringVelocity:0.1f + options:UIViewAnimationOptionBeginFromCurrentState + animations:animationBlock + completion:nil]; // Reset the focused index flag self.focusedIndex = -1; } -- (void)sendIndexChangedEventActions -{ +- (void)sendIndexChangedEventActions { // Trigger the action event for any targets that were [self sendActionsForControlEvents:UIControlEventValueChanged]; // Trigger the block if it is set if (self.segmentTappedHandler) { - self.segmentTappedHandler(self.selectedSegmentIndex, - self.selectedSegmentReversed); + self.segmentTappedHandler(self.selectedSegmentIndex, self.selectedSegmentReversed); } } @@ -1075,8 +1085,7 @@ - (void)sendIndexChangedEventActions - (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request - defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)) -{ + defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)) { CGRect frame = defaultRegion.rect; // Determine which segment the pointer is in @@ -1093,8 +1102,7 @@ - (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction } - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction - styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)) -{ + styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)) { // Fetch which segment was selected NSInteger segment = [(NSNumber *)region.identifier integerValue]; @@ -1102,7 +1110,8 @@ - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction CGRect frame = [self frameForSegmentAtIndex:segment]; // Create a preview link to the container view containing the item and arrow - UITargetedPreview *preview = [[UITargetedPreview alloc] initWithView:[self.segments[segment] containerView]]; + UITargetedPreview *preview = + [[UITargetedPreview alloc] initWithView:[self.segments[segment] containerView]]; // Define the selection shape as the size of the segment with the thumb's corner radius UIPointerShape *shape = [UIPointerShape shapeWithRoundedRect:frame @@ -1112,7 +1121,7 @@ - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction UIPointerEffect *effect = nil; if (segment == self.selectedSegmentIndex) { effect = [UIPointerLiftEffect effectWithPreview:preview]; - } else { // Un-selected segments + } else { // Un-selected segments effect = [UIPointerHighlightEffect effectWithPreview:preview]; } @@ -1122,27 +1131,22 @@ - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction - (void)pointerInteraction:(UIPointerInteraction *)interaction willEnterRegion:(UIPointerRegion *)region - animator:(id)animator API_AVAILABLE(ios(13.4)) -{ + animator:(id)animator API_AVAILABLE(ios(13.4)) { NSInteger segment = [(NSNumber *)region.identifier integerValue]; NSSet *selectedSegments = [NSSet setWithArray:@[@(segment), @(self.selectedSegmentIndex)]]; // Animate the separator views fading in and out to match - [animator addAnimations:^{ - [self refreshSeparatorViewsForSelectedIndexes:selectedSegments]; - }]; + [animator addAnimations:^{ [self refreshSeparatorViewsForSelectedIndexes:selectedSegments]; }]; } - (void)pointerInteraction:(UIPointerInteraction *)interaction willExitRegion:(UIPointerRegion *)region - animator:(id)animator API_AVAILABLE(ios(13.4)) -{ + animator:(id)animator API_AVAILABLE(ios(13.4)) { // Restore the thumb view self.trackView.clipsToBounds = YES; - [animator addAnimations:^{ - [self refreshSeparatorViewsForSelectedIndex:self.selectedSegmentIndex]; - }]; + [animator + addAnimations:^{ [self refreshSeparatorViewsForSelectedIndex:self.selectedSegmentIndex]; }]; } #pragma mark - Accessors - @@ -1150,9 +1154,10 @@ - (void)pointerInteraction:(UIPointerInteraction *)interaction // ----------------------------------------------- // Selected Item Index -- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex animated:(BOOL)animated -{ - if (self.selectedSegmentIndex == selectedSegmentIndex) { return; } +- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex animated:(BOOL)animated { + if (self.selectedSegmentIndex == selectedSegmentIndex) { + return; + } // Set the new value _selectedSegmentIndex = selectedSegmentIndex; @@ -1200,35 +1205,40 @@ - (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex animated:(BOOL)a options:UIViewAnimationOptionBeginFromCurrentState animations:animationBlock completion:nil]; - - } // ----------------------------------------------- // Selected Item Reversed -- (void)setSelectedSegmentReversed:(BOOL)selectedSegmentReversed -{ - if (self.selectedSegmentIndex < 0) { return; } +- (void)setSelectedSegmentReversed:(BOOL)selectedSegmentReversed { + if (self.selectedSegmentIndex < 0) { + return; + } TOSegmentedControlSegment *segment = self.segments[self.selectedSegmentIndex]; - if (segment.isReversible == NO) { return; } + if (segment.isReversible == NO) { + return; + } segment.isReversed = selectedSegmentReversed; } -- (BOOL)selectedSegmentReversed -{ - if (self.selectedSegmentIndex < 0) { return NO; } +- (BOOL)selectedSegmentReversed { + if (self.selectedSegmentIndex < 0) { + return NO; + } TOSegmentedControlSegment *segment = self.segments[self.selectedSegmentIndex]; - if (segment.isReversible == NO) { return NO; } + if (segment.isReversible == NO) { + return NO; + } return segment.isReversed; } // ----------------------------------------------- // Items -- (void)setItems:(NSArray *)items -{ - if (items == _items) { return; } +- (void)setItems:(NSArray *)items { + if (items == _items) { + return; + } // Remove all current items [self removeAllSegments]; @@ -1237,9 +1247,9 @@ - (void)setItems:(NSArray *)items _items = [self sanitizedItemArrayWithItems:items]; // Create the list of item objects to track their state - _segments = [TOSegmentedControlSegment segmentsWithObjects:_items - forSegmentedControl:self].mutableCopy; - + _segments = + [TOSegmentedControlSegment segmentsWithObjects:_items forSegmentedControl:self].mutableCopy; + // Update the number of separators [self updateSeparatorViewCount]; @@ -1253,8 +1263,7 @@ - (void)setItems:(NSArray *)items // ----------------------------------------------- // Corner Radius -- (void)setCornerRadius:(CGFloat)cornerRadius -{ +- (void)setCornerRadius:(CGFloat)cornerRadius { if (cornerRadius == _cornerRadius) { return; } @@ -1263,14 +1272,12 @@ - (void)setCornerRadius:(CGFloat)cornerRadius [self _updateCornerRadius]; } -- (CGFloat)_cornerRadiusValue -{ +- (CGFloat)_cornerRadiusValue { const BOOL isCapsuleShape = _cornerRadius == TOSegmentendControlCapsuleCornerRadius; return isCapsuleShape ? CGRectGetHeight(self.trackView.frame) / 2.0f : _cornerRadius; } -- (void)_updateCornerRadius -{ +- (void)_updateCornerRadius { const CGFloat cornerRadius = [self _cornerRadiusValue]; self.trackView.layer.cornerRadius = cornerRadius; self.thumbView.layer.cornerRadius = (cornerRadius - _thumbInset) + 1.0f; @@ -1279,16 +1286,17 @@ - (void)_updateCornerRadius // ----------------------------------------------- // Thumb Color -- (void)setThumbColor:(UIColor *)thumbColor -{ +- (void)setThumbColor:(UIColor *)thumbColor { self.thumbView.backgroundColor = thumbColor; - if (self.thumbView.backgroundColor != nil) { return; } + if (self.thumbView.backgroundColor != nil) { + return; + } // On iOS 12 and below, simply set the thumb view to be white self.thumbView.backgroundColor = [UIColor whiteColor]; - // For iOS 13 and up, create a dynamic provider that will trigger a color change - #ifdef __IPHONE_13_0 +// For iOS 13 and up, create a dynamic provider that will trigger a color change +#ifdef __IPHONE_13_0 if (@available(iOS 13.0, *)) { // Create the provider block that will trigger each time the trait collection changes id dynamicColorProvider = ^UIColor *(UITraitCollection *traitCollection) { @@ -1304,29 +1312,31 @@ - (void)setThumbColor:(UIColor *)thumbColor // Assign the dynamic color to the view self.thumbView.backgroundColor = [UIColor colorWithDynamicProvider:dynamicColorProvider]; } - #endif +#endif +} +- (UIColor *)thumbColor { + return self.thumbView.backgroundColor; } -- (UIColor *)thumbColor { return self.thumbView.backgroundColor; } // ----------------------------------------------- // Background Color -- (void)setBackgroundColor:(UIColor *)backgroundColor -{ +- (void)setBackgroundColor:(UIColor *)backgroundColor { [super setBackgroundColor:[UIColor clearColor]]; _trackView.backgroundColor = backgroundColor; // Exit out if we don't need to reset to defaults - if (_trackView.backgroundColor != nil) { return; } + if (_trackView.backgroundColor != nil) { + return; + } // Set the default color for iOS 12 and below backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.08f alpha:0.06666f]; _trackView.backgroundColor = backgroundColor; - // For iOS 13 and up, create a dynamic provider that will trigger on trait changes - #ifdef __IPHONE_13_0 +// For iOS 13 and up, create a dynamic provider that will trigger on trait changes +#ifdef __IPHONE_13_0 if (@available(iOS 13.0, *)) { - // Create the provider block that will trigger each time the trait collection changes id dynamicColorProvider = ^UIColor *(UITraitCollection *traitCollection) { // Dark color @@ -1341,22 +1351,23 @@ - (void)setBackgroundColor:(UIColor *)backgroundColor // Assign the dynamic color to the view _trackView.backgroundColor = [UIColor colorWithDynamicProvider:dynamicColorProvider]; } - #endif +#endif +} +- (UIColor *)backgroundColor { + return self.trackView.backgroundColor; } -- (UIColor *)backgroundColor { return self.trackView.backgroundColor; } // ----------------------------------------------- // Separator Color -- (void)setSeparatorColor:(UIColor *)separatorColor -{ +- (void)setSeparatorColor:(UIColor *)separatorColor { _separatorColor = separatorColor; if (_separatorColor == nil) { // Set the default color for iOS 12 and below separatorColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.08f alpha:0.1f]; - // On iOS 13 and up, set up a dynamic provider for dynamic light and dark colors - #ifdef __IPHONE_13_0 +// On iOS 13 and up, set up a dynamic provider for dynamic light and dark colors +#ifdef __IPHONE_13_0 if (@available(iOS 13.0, *)) { // Create the provider block that will trigger each time the trait collection changes id dynamicColorProvider = ^UIColor *(UITraitCollection *traitCollection) { @@ -1372,7 +1383,7 @@ - (void)setSeparatorColor:(UIColor *)separatorColor // Assign the dynamic color to the view separatorColor = [UIColor colorWithDynamicProvider:dynamicColorProvider]; } - #endif +#endif _separatorColor = separatorColor; } @@ -1385,18 +1396,17 @@ - (void)setSeparatorColor:(UIColor *)separatorColor // ----------------------------------------------- // Item Color -- (void)setItemColor:(UIColor *)itemColor -{ +- (void)setItemColor:(UIColor *)itemColor { _itemColor = itemColor; if (_itemColor == nil) { _itemColor = [UIColor blackColor]; - // Assign the dynamic label color on iOS 13 and up - #ifdef __IPHONE_13_0 +// Assign the dynamic label color on iOS 13 and up +#ifdef __IPHONE_13_0 if (@available(iOS 13.0, *)) { _itemColor = [UIColor labelColor]; } - #endif +#endif } // Set each item to the color @@ -1408,18 +1418,17 @@ - (void)setItemColor:(UIColor *)itemColor //------------------------------------------------- // Selected Item Color -- (void)setSelectedItemColor:(UIColor *)selectedItemColor -{ +- (void)setSelectedItemColor:(UIColor *)selectedItemColor { _selectedItemColor = selectedItemColor; if (_selectedItemColor == nil) { _selectedItemColor = [UIColor blackColor]; - // Assign the dynamic label color on iOS 13 and up - #ifdef __IPHONE_13_0 +// Assign the dynamic label color on iOS 13 and up +#ifdef __IPHONE_13_0 if (@available(iOS 13.0, *)) { _selectedItemColor = [UIColor labelColor]; } - #endif +#endif } // Set each item to the color @@ -1431,8 +1440,7 @@ - (void)setSelectedItemColor:(UIColor *)selectedItemColor // ----------------------------------------------- // Text Font -- (void)setTextFont:(UIFont *)textFont -{ +- (void)setTextFont:(UIFont *)textFont { _textFont = textFont; if (_textFont == nil) { _textFont = [UIFont systemFontOfSize:13.0f weight:UIFontWeightMedium]; @@ -1447,8 +1455,7 @@ - (void)setTextFont:(UIFont *)textFont // ----------------------------------------------- // Selected Text Font -- (void)setSelectedTextFont:(UIFont *)selectedTextFont -{ +- (void)setSelectedTextFont:(UIFont *)selectedTextFont { _selectedTextFont = selectedTextFont; if (_selectedTextFont == nil) { _selectedTextFont = [UIFont systemFontOfSize:13.0f weight:UIFontWeightSemibold]; @@ -1463,8 +1470,7 @@ - (void)setSelectedTextFont:(UIFont *)selectedTextFont // ----------------------------------------------- // Thumb Inset -- (void)setThumbInset:(CGFloat)thumbInset -{ +- (void)setThumbInset:(CGFloat)thumbInset { _thumbInset = thumbInset; self.thumbView.layer.cornerRadius = ([self _cornerRadiusValue] - _thumbInset) + 1.0f; } @@ -1472,59 +1478,74 @@ - (void)setThumbInset:(CGFloat)thumbInset // ----------------------------------------------- // Shadow Properties -- (void)setThumbShadowOffset:(CGFloat)thumbShadowOffset {self.thumbView.layer.shadowOffset = (CGSize){0.0f, thumbShadowOffset}; } -- (CGFloat)thumbShadowOffset { return self.thumbView.layer.shadowOffset.height; } +- (void)setThumbShadowOffset:(CGFloat)thumbShadowOffset { + self.thumbView.layer.shadowOffset = (CGSize){0.0f, thumbShadowOffset}; +} +- (CGFloat)thumbShadowOffset { + return self.thumbView.layer.shadowOffset.height; +} -- (void)setThumbShadowOpacity:(CGFloat)thumbShadowOpacity { self.thumbView.layer.shadowOpacity = thumbShadowOpacity; } -- (CGFloat)thumbShadowOpacity { return self.thumbView.layer.shadowOpacity; } +- (void)setThumbShadowOpacity:(CGFloat)thumbShadowOpacity { + self.thumbView.layer.shadowOpacity = thumbShadowOpacity; +} +- (CGFloat)thumbShadowOpacity { + return self.thumbView.layer.shadowOpacity; +} -- (void)setThumbShadowRadius:(CGFloat)thumbShadowRadius { self.thumbView.layer.shadowRadius = thumbShadowRadius; } -- (CGFloat)thumbShadowRadius { return self.thumbView.layer.shadowRadius; } +- (void)setThumbShadowRadius:(CGFloat)thumbShadowRadius { + self.thumbView.layer.shadowRadius = thumbShadowRadius; +} +- (CGFloat)thumbShadowRadius { + return self.thumbView.layer.shadowRadius; +} // ----------------------------------------------- // Number of segments -- (NSInteger)numberOfSegments { return self.segments.count; } +- (NSInteger)numberOfSegments { + return self.segments.count; +} // ----------------------------------------------- // Setting all reversible indexes -- (void)setReversibleSegmentIndexes:(NSArray *)reversibleSegmentIndexes -{ +- (void)setReversibleSegmentIndexes:(NSArray *)reversibleSegmentIndexes { for (NSInteger i = 0; i < self.numberOfSegments; i++) { BOOL reversible = [reversibleSegmentIndexes indexOfObject:@(i)] != NSNotFound; [self setReversible:reversible forSegmentAtIndex:i]; } } -- (NSArray *)reversibleSegmentIndexes -{ +- (NSArray *)reversibleSegmentIndexes { NSMutableArray *array = [NSMutableArray array]; for (NSInteger i = 0; i < self.numberOfSegments; i++) { if ([self isReversibleForSegmentAtIndex:i]) { [array addObject:@(i)]; } } - + return [NSArray arrayWithArray:array]; } -- (BOOL)hasNoSegments { return self.segments.count <= 0; } +- (BOOL)hasNoSegments { + return self.segments.count <= 0; +} #pragma mark - Image Creation and Management - -- (UIImage *)arrowImage -{ +- (UIImage *)arrowImage { // Retrieve from the image table UIImage *arrowImage = [self.imageTable objectForKey:kTOSegmentedControlArrowImage]; - if (arrowImage != nil) { return arrowImage; } + if (arrowImage != nil) { + return arrowImage; + } // Generate for the first time UIGraphicsBeginImageContextWithOptions((CGSize){8.0f, 4.0f}, NO, 0.0f); { - UIBezierPath* bezierPath = [UIBezierPath bezierPath]; - [bezierPath moveToPoint: CGPointMake(7.25, 0.75)]; - [bezierPath addLineToPoint: CGPointMake(4, 3.25)]; - [bezierPath addLineToPoint: CGPointMake(0.75, 0.75)]; + UIBezierPath *bezierPath = [UIBezierPath bezierPath]; + [bezierPath moveToPoint:CGPointMake(7.25, 0.75)]; + [bezierPath addLineToPoint:CGPointMake(4, 3.25)]; + [bezierPath addLineToPoint:CGPointMake(0.75, 0.75)]; [UIColor.blackColor setStroke]; bezierPath.lineWidth = 1.5; bezierPath.lineCapStyle = kCGLineCapRound; @@ -1543,14 +1564,16 @@ - (UIImage *)arrowImage return arrowImage; } -- (UIImage *)separatorImage -{ +- (UIImage *)separatorImage { UIImage *separatorImage = [self.imageTable objectForKey:kTOSegmentedControlSeparatorImage]; - if (separatorImage != nil) { return separatorImage; } + if (separatorImage != nil) { + return separatorImage; + } UIGraphicsBeginImageContextWithOptions((CGSize){1.0f, 3.0f}, NO, 0.0f); { - UIBezierPath* separatorPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 1, 3) cornerRadius:0.5]; + UIBezierPath *separatorPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 1, 3) + cornerRadius:0.5]; [UIColor.blackColor setFill]; [separatorPath fill]; separatorImage = UIGraphicsGetImageFromCurrentImageContext(); @@ -1558,22 +1581,24 @@ - (UIImage *)separatorImage UIGraphicsEndImageContext(); // Format image to be resizable and tint-able. - separatorImage = [separatorImage resizableImageWithCapInsets:(UIEdgeInsets){1.0f, 0.0f, 1.0f, 0.0f} - resizingMode:UIImageResizingModeTile]; + separatorImage = + [separatorImage resizableImageWithCapInsets:(UIEdgeInsets){1.0f, 0.0f, 1.0f, 0.0f} + resizingMode:UIImageResizingModeTile]; separatorImage = [separatorImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; return separatorImage; } -- (NSMapTable *)imageTable -{ +- (NSMapTable *)imageTable { // The map table is a global instance that allows all instances of // segmented controls to efficiently share the same images. // The images themselves are weakly referenced, so they will be cleaned // up from memory when all segmented controls using them are deallocated. - if (_imageTable) { return _imageTable; } + if (_imageTable) { + return _imageTable; + } _imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory]; return _imageTable;