Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions NYSegmentedControl/NYSegment.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

#import "NYSegment.h"

static CGFloat const kMinimumSegmentWidth = 68.0f;

@implementation NYSegment

- (instancetype)initWithTitle:(NSString *)title {
Expand All @@ -37,7 +35,7 @@ - (id)initWithFrame:(CGRect)frame {

- (CGSize)sizeThatFits:(CGSize)size {
CGSize sizeThatFits = [self.titleLabel sizeThatFits:size];
return CGSizeMake(MAX(sizeThatFits.width * 1.4f, kMinimumSegmentWidth), sizeThatFits.height);
return CGSizeMake(sizeThatFits.width * 1.4f, sizeThatFits.height);
}

@end
15 changes: 15 additions & 0 deletions NYSegmentedControl/NYSegmentedControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@
*/
@property (nonatomic) NSUInteger selectedSegmentIndex;

/**
The width of the selected segment indicator's border
*/
@property (nonatomic) CGFloat minimumSegmentWidth UI_APPEARANCE_SELECTOR;

/**
Initializes and returns a control with segments having the specified titles.

Expand All @@ -139,6 +144,16 @@
*/
- (instancetype)initWithItems:(NSArray *)items;

/**
Initializes and returns a control with segments having the specified titles with custom selected segment indicator.

@param items An array of NSString objects representing the titles of segments in the control.
@param segmentIndicatorView A custom `UIView` to use for selected segment indicator

@return An initialized NYSegmentedControl object, or nil if it could not be created.
*/
- (instancetype)initWithItems:(NSArray *)items segmentIndicatorView:(UIView *)segmentIndicatorView;

/**
Inserts a segment at the specified index.

Expand Down
99 changes: 70 additions & 29 deletions NYSegmentedControl/NYSegmentedControl.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

@interface NYSegmentedControl ()

@property NSArray *segments;
@property NYSegmentIndicator *selectedSegmentIndicator;
@property (copy, nonatomic) NSArray *segments;
@property (strong, nonatomic) NYSegmentIndicator *selectedSegmentIndicator;

- (void)moveSelectedSegmentIndicatorToSegmentAtIndex:(NSUInteger)index animated:(BOOL)animated;
- (CGRect)indicatorFrameForSegment:(NYSegment *)segment;
Expand All @@ -28,29 +28,29 @@ + (Class)layerClass {
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];

if (self) {
[self initialize];
}
self = [self initWithItems:nil segmentIndicatorView:nil];

return self;
}

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

if (self) {
[self initialize];
}
self = [self initWithItems:nil segmentIndicatorView:nil];

return self;
}

- (instancetype)initWithItems:(NSArray *)items {
self = [self initWithFrame:CGRectZero];
self = [self initWithItems:items segmentIndicatorView:nil];

return self;
}

- (instancetype)initWithItems:(NSArray *)items segmentIndicatorView:(UIView *)segmentIndicatorView {
self = [super initWithFrame:CGRectZero];

if (self) {
[self initializeWithSegmentIndicatorView:segmentIndicatorView];

NSMutableArray *mutableSegments = [NSMutableArray array];

for (NSString *segmentTitle in items) {
Expand All @@ -66,7 +66,7 @@ - (instancetype)initWithItems:(NSArray *)items {
return self;
}

- (void)initialize {
- (void)initializeWithSegmentIndicatorView:(UIView *)segmentIndicatorView {
// We need to directly access the ivars for UIAppearance properties in the initializer
_titleFont = [UIFont systemFontOfSize:13.0f];
_titleTextColor = [UIColor blackColor];
Expand All @@ -77,6 +77,7 @@ - (void)initialize {
_segmentIndicatorAnimationDuration = 0.15f;
_gradientTopColor = [UIColor colorWithRed:0.21f green:0.21f blue:0.21f alpha:1.0f];
_gradientBottomColor = [UIColor colorWithRed:0.16f green:0.16f blue:0.16f alpha:1.0f];
_minimumSegmentWidth = 68.f;

self.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.layer.masksToBounds = YES;
Expand All @@ -88,7 +89,11 @@ - (void)initialize {
self.opaque = NO;
self.segments = [NSArray array];

self.selectedSegmentIndicator = [[NYSegmentIndicator alloc] initWithFrame:CGRectZero];
if (!segmentIndicatorView) {
segmentIndicatorView = [[NYSegmentIndicator alloc] initWithFrame:CGRectZero];
}

self.selectedSegmentIndicator = (NYSegmentIndicator *)segmentIndicatorView;
self.drawsSegmentIndicatorGradientBackground = YES;
[self addSubview:self.selectedSegmentIndicator];
}
Expand All @@ -97,7 +102,7 @@ - (CGSize)sizeThatFits:(CGSize)size {
CGFloat maxSegmentWidth = 0.0f;

for (NYSegment *segment in self.segments) {
CGFloat segmentWidth = [segment sizeThatFits:size].width;
CGFloat segmentWidth = MAX([segment sizeThatFits:size].width, self.minimumSegmentWidth);
if (segmentWidth > maxSegmentWidth) {
maxSegmentWidth = segmentWidth;
}
Expand Down Expand Up @@ -329,7 +334,9 @@ - (CGFloat)borderWidth {

- (void)setCornerRadius:(CGFloat)cornerRadius {
self.layer.cornerRadius = cornerRadius;
self.selectedSegmentIndicator.cornerRadius = cornerRadius * ((self.frame.size.height - self.segmentIndicatorInset * 2) / self.frame.size.height);
if ([self.selectedSegmentIndicator respondsToSelector:@selector(setCornerRadius:)]) {
self.selectedSegmentIndicator.cornerRadius = cornerRadius * ((self.frame.size.height - self.segmentIndicatorInset * 2) / self.frame.size.height);
}
[self setNeedsDisplay];
}

Expand All @@ -338,16 +345,25 @@ - (CGFloat)cornerRadius {
}

- (void)setDrawsSegmentIndicatorGradientBackground:(BOOL)drawsSegmentIndicatorGradientBackground {
self.selectedSegmentIndicator.drawsGradientBackground = drawsSegmentIndicatorGradientBackground;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(setDrawsGradientBackground:)]) {
self.selectedSegmentIndicator.drawsGradientBackground = drawsSegmentIndicatorGradientBackground;
}
}

- (BOOL)drawsSegmentIndicatorGradientBackground {
return self.selectedSegmentIndicator.drawsGradientBackground;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(drawsGradientBackground)]) {
return self.selectedSegmentIndicator.drawsGradientBackground;
}

return NO;
}

- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
self.selectedSegmentIndicator.cornerRadius = self.cornerRadius * ((self.frame.size.height - self.segmentIndicatorInset * 2) / self.frame.size.height);

if ([self.selectedSegmentIndicator respondsToSelector:@selector(setCornerRadius:)]) {
self.selectedSegmentIndicator.cornerRadius = self.cornerRadius * ((self.frame.size.height - self.segmentIndicatorInset * 2) / self.frame.size.height);
}
}

- (void)setSegmentIndicatorBackgroundColor:(UIColor *)segmentIndicatorBackgroundColor {
Expand All @@ -360,40 +376,65 @@ - (UIColor *)segmentIndicatorBackgroundColor {

- (void)setSegmentIndicatorInset:(CGFloat)segmentIndicatorInset {
_segmentIndicatorInset = segmentIndicatorInset;
self.selectedSegmentIndicator.cornerRadius = self.cornerRadius * ((self.frame.size.height - self.segmentIndicatorInset * 2) / self.frame.size.height);
if ([self.selectedSegmentIndicator respondsToSelector:@selector(setCornerRadius:)]) {
self.selectedSegmentIndicator.cornerRadius = self.cornerRadius * ((self.frame.size.height - self.segmentIndicatorInset * 2) / self.frame.size.height);
}
[self setNeedsLayout];
}

- (void)setSegmentIndicatorGradientTopColor:(UIColor *)segmentIndicatorGradientTopColor {
self.selectedSegmentIndicator.gradientTopColor = segmentIndicatorGradientTopColor;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(setGradientTopColor:)]) {
self.selectedSegmentIndicator.gradientTopColor = segmentIndicatorGradientTopColor;
}
}

- (UIColor *)segmentIndicatorGradientTopColor {
return self.selectedSegmentIndicator.gradientTopColor;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(gradientTopColor)]) {
return self.selectedSegmentIndicator.gradientTopColor;
}

return nil;
}

- (void)setSegmentIndicatorGradientBottomColor:(UIColor *)segmentIndicatorGradientBottomColor {
self.selectedSegmentIndicator.gradientBottomColor = segmentIndicatorGradientBottomColor;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(setGradientBottomColor:)]) {
self.selectedSegmentIndicator.gradientBottomColor = segmentIndicatorGradientBottomColor;
}
}

- (UIColor *)segmentIndicatorGradientBottomColor {
return self.selectedSegmentIndicator.gradientBottomColor;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(gradientBottomColor)]) {
return self.selectedSegmentIndicator.gradientBottomColor;
}

return nil;
}

- (void)setSegmentIndicatorBorderColor:(UIColor *)segmentIndicatorBorderColor {
self.selectedSegmentIndicator.borderColor = segmentIndicatorBorderColor;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(setBorderColor:)]) {
self.selectedSegmentIndicator.borderColor = segmentIndicatorBorderColor;
}
}

- (UIColor *)segmentIndicatorBorderColor {
return self.selectedSegmentIndicator.borderColor;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(borderColor)]) {
return self.selectedSegmentIndicator.borderColor;
}

return nil;
}

- (void)setSegmentIndicatorBorderWidth:(CGFloat)segmentIndicatorBorderWidth {
self.selectedSegmentIndicator.borderWidth = segmentIndicatorBorderWidth;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(setBorderWidth:)]) {
self.selectedSegmentIndicator.borderWidth = segmentIndicatorBorderWidth;
}
}

- (CGFloat)segmentIndicatorBorderWidth {
return self.selectedSegmentIndicator.borderWidth;
if ([self.selectedSegmentIndicator respondsToSelector:@selector(borderWidth)]) {
return self.selectedSegmentIndicator.borderWidth;
}
return 0.f;
}

- (void)setTitleFont:(UIFont *)titleFont {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
0E3CBE3C18DECF82001EC237 /* NYSegmentedControlDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CBE3B18DECF82001EC237 /* NYSegmentedControlDemoTests.m */; };
0E3CBE4918DECFAC001EC237 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CBE4618DECFAC001EC237 /* AppDelegate.m */; };
0E3CBE4A18DECFAC001EC237 /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CBE4818DECFAC001EC237 /* DemoViewController.m */; };
2A4F2A58197DB1D000ADEB96 /* NYSegmentIndicatorSingleLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A4F2A57197DB1D000ADEB96 /* NYSegmentIndicatorSingleLine.m */; };
C53E59451932DA7100087BCD /* NYSegment.m in Sources */ = {isa = PBXBuildFile; fileRef = C53E59401932DA7100087BCD /* NYSegment.m */; };
C53E59461932DA7100087BCD /* NYSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = C53E59421932DA7100087BCD /* NYSegmentedControl.m */; };
C53E59471932DA7100087BCD /* NYSegmentIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = C53E59441932DA7100087BCD /* NYSegmentIndicator.m */; };
Expand Down Expand Up @@ -53,6 +54,8 @@
0E3CBE4618DECFAC001EC237 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
0E3CBE4718DECFAC001EC237 /* DemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = "<group>"; };
0E3CBE4818DECFAC001EC237 /* DemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoViewController.m; sourceTree = "<group>"; };
2A4F2A56197DB1D000ADEB96 /* NYSegmentIndicatorSingleLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NYSegmentIndicatorSingleLine.h; sourceTree = "<group>"; };
2A4F2A57197DB1D000ADEB96 /* NYSegmentIndicatorSingleLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NYSegmentIndicatorSingleLine.m; sourceTree = "<group>"; };
C53E593F1932DA7100087BCD /* NYSegment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NYSegment.h; sourceTree = "<group>"; };
C53E59401932DA7100087BCD /* NYSegment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NYSegment.m; sourceTree = "<group>"; };
C53E59411932DA7100087BCD /* NYSegmentedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NYSegmentedControl.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -124,6 +127,8 @@
0E3CBE4818DECFAC001EC237 /* DemoViewController.m */,
0E3CBE2818DECF82001EC237 /* Images.xcassets */,
0E3CBE1718DECF82001EC237 /* Supporting Files */,
2A4F2A56197DB1D000ADEB96 /* NYSegmentIndicatorSingleLine.h */,
2A4F2A57197DB1D000ADEB96 /* NYSegmentIndicatorSingleLine.m */,
);
path = NYSegmentedControlDemo;
sourceTree = "<group>";
Expand Down Expand Up @@ -269,6 +274,7 @@
buildActionMask = 2147483647;
files = (
C53E59451932DA7100087BCD /* NYSegment.m in Sources */,
2A4F2A58197DB1D000ADEB96 /* NYSegmentIndicatorSingleLine.m in Sources */,
0E3CBE4A18DECFAC001EC237 /* DemoViewController.m in Sources */,
C53E59471932DA7100087BCD /* NYSegmentIndicator.m in Sources */,
0E3CBE4918DECFAC001EC237 /* AppDelegate.m in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions NYSegmentedControlDemo/NYSegmentedControlDemo/DemoViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#import "DemoViewController.h"
#import "NYSegmentedControl.h"
#import "NYSegmentIndicatorSingleLine.h"

@interface DemoViewController ()

Expand Down Expand Up @@ -85,6 +86,22 @@ - (void)viewDidLoad {
foursquareSegmentedControlBackgroundView.center = foursquareSegmentedControl.center;
[lightControlExampleView addSubview:foursquareSegmentedControl];

NYSegmentIndicatorSingleLine *segmentIndicatorLineView = [[NYSegmentIndicatorSingleLine alloc] initWithFrame:CGRectZero];
NYSegmentedControl *plainSegmentedControl = [[NYSegmentedControl alloc] initWithItems:@[@"Left", @"Right"]
segmentIndicatorView:segmentIndicatorLineView];
plainSegmentedControl.titleTextColor = [UIColor grayColor];
plainSegmentedControl.selectedTitleTextColor = [UIColor redColor];
plainSegmentedControl.selectedTitleFont = [UIFont systemFontOfSize:13.0f];
plainSegmentedControl.backgroundColor = lightControlExampleView.backgroundColor;
plainSegmentedControl.borderWidth = 0.0f;
plainSegmentedControl.segmentIndicatorBorderWidth = 0.0f;
plainSegmentedControl.segmentIndicatorInset = 1.0f;
plainSegmentedControl.cornerRadius = 0.f;
plainSegmentedControl.minimumSegmentWidth = 50.f;
[plainSegmentedControl sizeToFit];
plainSegmentedControl.center = CGPointMake(lightControlExampleView.center.x, lightControlExampleView.center.y + 100.0f);
[lightControlExampleView addSubview:plainSegmentedControl];

UIView *darkControlExampleView = [[UIView alloc] initWithFrame:self.view.bounds];
darkControlExampleView.backgroundColor = [UIColor colorWithWhite:0.2f alpha:1.0f];
darkControlExampleView.hidden = YES;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// NYSegmentIndicatorSingleLine.h
//
// Created by Andrew Podkovyrin on 22/07/14.
// Copyright (c) 2014 Neal Young. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface NYSegmentIndicatorSingleLine : UIView

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// NYSegmentIndicatorSingleLine.m
//
// Created by Andrew Podkovyrin on 22/07/14.
// Copyright (c) 2014 Neal Young. All rights reserved.
//

#import "NYSegmentIndicatorSingleLine.h"

@interface NYSegmentIndicatorSingleLine ()

@property (strong, readwrite, nonatomic) UIView *bottomLineView;

@end


@implementation NYSegmentIndicatorSingleLine

- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.opaque = NO;
self.userInteractionEnabled = NO;

self.bottomLineView = [[UIView alloc] initWithFrame:CGRectZero];
self.bottomLineView.backgroundColor = [UIColor redColor];
[self addSubview:self.bottomLineView];
}
return self;
}

- (void)layoutSubviews {
[super layoutSubviews];

self.bottomLineView.frame = CGRectMake(0.f, CGRectGetHeight(self.bounds) - 1.f, CGRectGetWidth(self.bounds), 1.f);
}

@end