From 8f4f62ed44d8319a432e90d2b170e52059ff46d1 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Tue, 16 Jan 2018 20:12:06 -0700 Subject: [PATCH 01/33] Adding methods for dynamic tick marks --- HUMSliderSample.xcodeproj/project.pbxproj | 3 ++ Library/HUMSlider.h | 23 ++++++++- Library/HUMSlider.m | 58 ++++++++++++++++++++++- 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/HUMSliderSample.xcodeproj/project.pbxproj b/HUMSliderSample.xcodeproj/project.pbxproj index 06d2495..9e42070 100644 --- a/HUMSliderSample.xcodeproj/project.pbxproj +++ b/HUMSliderSample.xcodeproj/project.pbxproj @@ -182,6 +182,7 @@ TargetAttributes = { 9BA867DA1A4DF3B900121ED5 = { CreatedOnToolsVersion = 6.1.1; + DevelopmentTeam = ZAR5QX7MAH; }; 9BA867F31A4DF3B900121ED5 = { CreatedOnToolsVersion = 6.1.1; @@ -375,6 +376,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = ZAR5QX7MAH; INFOPLIST_FILE = HUMSliderSample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -386,6 +388,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = ZAR5QX7MAH; INFOPLIST_FILE = HUMSliderSample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index 4ad3db8..fe0ae37 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -13,6 +13,11 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { HUMSliderSideRight }; +@interface Tick : NSObject +- (id)initWithPosition:(double)position; +@property double position; //Number between 0 and 1 indicating the slider position of the tick. +@end + /** * A slider which pops up ticks and saturates/desaturates images when the user adjusts * a slider for better feedback to the user about their adjustment. @@ -23,6 +28,8 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { @interface HUMSlider : UISlider #pragma mark - Ticks +///Tick positions, specified as "Tick" objects with values between 0 and 1 +@property (atomic) NSMutableArray *ticks; ///The color of the ticks you wish to pop up. Defaults to dark gray. @property (nonatomic) UIColor *tickColor; @@ -58,6 +65,20 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { #pragma mark - Setters/Getters for individual sides +/** + * Inserts a tick at a position. + * + * @param tick. The tick with the set position between 0 and 1 + */ +- (void)addTick:(Tick*)tick; + +/** + * Removes the tick at the given index. . + * + * @param tick. The tick with the set position between 0 and 1 + */ +- (void)removeTickAtIndex:(uint)index; + /** * Sets the color to use as the fully-saturated color on selected side. * @@ -75,7 +96,7 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { /** * Sets the color to use as the desaturated color on selected side. * - * @param saturatedColor The UIColor to use + * @param desaturatedColor The UIColor to use * @param side The side you wish to set a desaturated color upon. */ - (void)setDesaturatedColor:(UIColor *)desaturatedColor forSide:(HUMSliderSide)side; diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 503122d..057ce28 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -19,10 +19,25 @@ static CGFloat const HUMImagePadding = 8; // Sizes -static CGFloat const HUMTickHeight = 6; -static CGFloat const HUMTickWidth = 1; +static CGFloat const HUMTickHeight = 8; +static CGFloat const HUMTickWidth = 2; + +@implementation Tick +// Constructor for a tick +- (id)initWithPosition:(double)position { + NSAssert(position >= 0 && position <= 1, @"Position must be between 0 and 1"); + self = [super init]; + if (self) { + self.position = position; + } + return self; +} +@end @interface HUMSlider () + + + @property (nonatomic) NSArray *tickViews; @property (nonatomic) NSArray *allTickBottomConstraints; @property (nonatomic) NSArray *leftTickRightConstraints; @@ -55,6 +70,9 @@ - (void)commonInit self.secondTickMovementAndimationDuration = HUMSecondTickDuration; self.nextTickAnimationDelay = HUMTickAnimationDelay; + //Private var init + self.ticks = [NSMutableArray new]; + //These will set the side colors. self.saturatedColor = [UIColor redColor]; self.desaturatedColor = [UIColor lightGrayColor]; @@ -96,6 +114,36 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder #pragma mark - Ticks +- (void)addTick:(Tick*)tick { + //[_ticks addObject:tick]; + + if ([_ticks count] == 0) { + [_ticks addObject:tick]; + } + else { + uint index = 1; + for (Tick *tick_itr in _ticks) { + if (tick_itr.position < tick.position) { + [_ticks insertObject:tick atIndex:index-1]; + break; + } + index ++; + } + } + + + + //NSSortDescriptor *sortDescriptor; + //sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"position" + ascending:YES]; +#warning - this shit doesn't sort! + //_ticks = [[_ticks sortedArrayUsingDescriptors:@[sortDescriptor]] mutableCopy]; +} + +- (void)removeTickAtIndex:(uint)index { + [_ticks removeObjectAtIndex:index]; +} + - (void)nukeOldTicks { for (UIView *tick in self.tickViews) { @@ -169,6 +217,11 @@ - (void)setupTicksAutolayout [self pinTickWidthAndHeight:nextToRight]; NSLayoutConstraint *rightBottom = [self pinTickBottom:nextToRight]; [bottoms addObject:rightBottom]; +#warning - clean up. +// int multiplier = 1; +// if (i == 3) { +// multiplier = 1; +// } // Pin the right of the next leftwards tick to the previous leftwards tick NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:nextToLeft @@ -738,6 +791,7 @@ - (CGFloat)trackYOrigin return CGRectGetMinY(trackRect); } +#warning - replace this with something more dynamic. - (CGFloat)segmentWidth { CGRect trackRect = [self trackRectForBounds:self.bounds]; From a674c6d3c291014abdb2e2c40f43c8bd7d46ece2 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Wed, 14 Feb 2018 20:49:47 -0700 Subject: [PATCH 02/33] Tick object, tick layout constraints. --- Library/HUMSlider.h | 10 ++- Library/HUMSlider.m | 205 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 181 insertions(+), 34 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index fe0ae37..bd02c09 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -62,6 +62,9 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { ///How long to wait between animating secondary ticks. Defaults to 0.025 seconds. @property (nonatomic) NSTimeInterval nextTickAnimationDelay; +///Turns the custom tick feature on and off. +@property (nonatomic) bool customTicksEnabled; + #pragma mark - Setters/Getters for individual sides @@ -70,7 +73,12 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { * * @param tick. The tick with the set position between 0 and 1 */ -- (void)addTick:(Tick*)tick; +- (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView; + +/** + * Refreshes the view in a custom way, in case you didn't do it for each tick addition. + */ +- (void)refreshView; /** * Removes the tick at the given index. . diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 057ce28..e5a87f1 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -20,7 +20,7 @@ // Sizes static CGFloat const HUMTickHeight = 8; -static CGFloat const HUMTickWidth = 2; +static CGFloat const HUMTickWidth = 1; @implementation Tick // Constructor for a tick @@ -36,8 +36,6 @@ - (id)initWithPosition:(double)position { @interface HUMSlider () - - @property (nonatomic) NSArray *tickViews; @property (nonatomic) NSArray *allTickBottomConstraints; @property (nonatomic) NSArray *leftTickRightConstraints; @@ -63,6 +61,8 @@ @implementation HUMSlider - (void)commonInit { + self.customTicksEnabled = true; + // Set default values. self.sectionCount = 9; self.tickAlphaAnimationDuration = HUMTickAlphaDuration; @@ -71,7 +71,7 @@ - (void)commonInit self.nextTickAnimationDelay = HUMTickAnimationDelay; //Private var init - self.ticks = [NSMutableArray new]; + self.ticks = [[NSMutableArray alloc] init]; //These will set the side colors. self.saturatedColor = [UIColor redColor]; @@ -114,30 +114,24 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder #pragma mark - Ticks -- (void)addTick:(Tick*)tick { - //[_ticks addObject:tick]; - - if ([_ticks count] == 0) { - [_ticks addObject:tick]; +- (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView { + if ([self.ticks count] == 0) { + [self.ticks addObject:tick]; } else { - uint index = 1; - for (Tick *tick_itr in _ticks) { - if (tick_itr.position < tick.position) { - [_ticks insertObject:tick atIndex:index-1]; + unsigned long index = [self.ticks count]; + for (Tick *tick_itr in [self.ticks reverseObjectEnumerator]) { + if (tick.position >= tick_itr.position) { + [self.ticks insertObject:tick atIndex:index]; break; } - index ++; + index --; } } - - - //NSSortDescriptor *sortDescriptor; - //sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"position" - ascending:YES]; -#warning - this shit doesn't sort! - //_ticks = [[_ticks sortedArrayUsingDescriptors:@[sortDescriptor]] mutableCopy]; + if (refreshView) { + [self setupTicks]; + } } - (void)removeTickAtIndex:(uint)index { @@ -157,25 +151,159 @@ - (void)nukeOldTicks [self layoutIfNeeded]; } +- (void)refreshView { + [self setupTicks]; +} + - (void)setupTicks { +// NSUInteger count = _ticks ? [_ticks count] : self.sectionCount; +// NSMutableArray *tickBuilder = [NSMutableArray array]; +// for (NSInteger i = 0; i < count; i++) { +// UIView *tick = [[UIView alloc] init]; +// tick.backgroundColor = self.tickColor; +// tick.alpha = 0; +// tick.translatesAutoresizingMaskIntoConstraints = NO; +// [self addSubview:tick]; +// [self sendSubviewToBack:tick]; +// [tickBuilder addObject:tick]; +// } +// +// self.tickViews = tickBuilder; + if (_customTicksEnabled && _ticks && [_ticks count] > 0) { + [self setupCustomTickViews]; + [self setupTicksAutoLayoutCustomWidths]; + } + else { + [self setupSpacedTickViews]; + [self setupTicksAutolayout]; + } +} + +- (void)setupSpacedTickViews { + [self createAndAddBlankTickViewsWithCount:(int)self.sectionCount]; +} + +- (void)setupCustomTickViews { + [self createAndAddBlankTickViewsWithCount:(int)[_ticks count]]; +} + +- (void)createAndAddBlankTickViewsWithCount:(int)count { NSMutableArray *tickBuilder = [NSMutableArray array]; - for (NSInteger i = 0; i < self.sectionCount; i++) { - UIView *tick = [[UIView alloc] init]; - tick.backgroundColor = self.tickColor; - tick.alpha = 0; - tick.translatesAutoresizingMaskIntoConstraints = NO; - [self addSubview:tick]; - [self sendSubviewToBack:tick]; + for (NSInteger i = 0; i < count; i++) { + UIView *tick = [self setupCommonTickViewAnddAddToSubview]; [tickBuilder addObject:tick]; } self.tickViews = tickBuilder; - [self setupTicksAutolayout]; +} + +- (UIView*)setupCommonTickViewAnddAddToSubview { + UIView *tick = [[UIView alloc] init]; + tick.backgroundColor = self.tickColor; + tick.alpha = 0; + tick.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:tick]; + [self sendSubviewToBack:tick]; + return tick; } #pragma mark Autolayout +#warning - this is called with zero tickViews and zero elements in _ticks +- (void)setupTicksAutoLayoutCustomWidths { + //Store the left, right and bottom constraints for some reason + NSMutableArray *bottoms = [NSMutableArray array]; + NSMutableArray *lefts = [NSMutableArray array]; + NSMutableArray *rights = [NSMutableArray array]; + + //Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. + NSMutableArray *positionDiffs = [NSMutableArray new]; + int tickCount = (int)[self.tickViews count]; + for (NSInteger i = 0; i <= tickCount; i++) { + double currentItem = i == tickCount ? [self trackWidth] : ((Tick*)self.ticks[i]).position; + double previousTime = i == 0 ? 0 : ((Tick*)self.ticks[i - 1]).position; + double zeroToOnePercentage = currentItem - previousTime; + double distanceDiff = zeroToOnePercentage * [self trackWidth]; + [positionDiffs insertObject:[NSNumber numberWithDouble: distanceDiff] atIndex:(i)]; + } + + //This is the new code to start at the first one. + for (NSInteger i = 0; i < [self.tickViews count]; i++) { + bool isFirst = i == 0 ? true : false; + bool isLast = i == tickCount - 1 ? true : false; + + UIView *currentItem = self.tickViews[i]; + UIView *previousItem = isFirst ? NULL : self.tickViews[i - 1]; + UIView *nextItem = isLast ? NULL : self.tickViews[i + 1]; + + NSLayoutConstraint *bottomConstraint = [self pinTickBottom:currentItem]; + [self addConstraint:bottomConstraint]; + [bottoms insertObject:bottomConstraint atIndex:i]; + [self pinTickWidthAndHeight:currentItem]; + + if (isFirst) { + CGFloat diff = [positionDiffs[i] doubleValue]; + // Pin the first tick to the left of the view. + NSLayoutConstraint *farLeft = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeLeft + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeLeft + multiplier:1 + constant:diff]; + [self addConstraint:farLeft]; + [lefts addObject:farLeft]; + } + else { //Left constraints for all but the first element. + CGFloat diff = [positionDiffs[i] doubleValue]; + // Pin the right of the next leftwards tick to the previous leftwards tick + NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeRight + relatedBy:NSLayoutRelationEqual + toItem:previousItem + attribute:NSLayoutAttributeLeft + multiplier:1 + constant:diff]; + [self addConstraint:left]; + [lefts addObject:left]; + } + + if (isLast) { + CGFloat diff = [positionDiffs[i + 1] doubleValue]; + // Pin the first tick to the left of the view. + NSLayoutConstraint *farRight = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeRight + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeRight + multiplier:1 + constant:diff]; + [self addConstraint:farRight]; + [rights addObject:farRight]; + } + else { //right constraints for all but the last element + CGFloat diff = [positionDiffs[i + 1] doubleValue]; + // Pin the right of the next leftwards tick to the previous leftwards tick + NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeLeft + relatedBy:NSLayoutRelationEqual + toItem:nextItem + attribute:NSLayoutAttributeRight + multiplier:1 + constant:diff]; + [self addConstraint:right]; + [rights addObject:right]; + } + } + + self.allTickBottomConstraints = bottoms; + self.leftTickRightConstraints = lefts; + self.rightTickLeftConstraints = rights; + + [self layoutIfNeeded]; +} + - (void)setupTicksAutolayout { NSMutableArray *bottoms = [NSMutableArray array]; @@ -254,6 +382,7 @@ - (void)setupTicksAutolayout [self layoutIfNeeded]; } +//Size of the tick itself. - (void)pinTickWidthAndHeight:(UIView *)currentTick { // Pin width of tick @@ -620,10 +749,15 @@ - (void)setTickColor:(UIColor *)tickColor - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { - // Update the width - [self updateLeftTickConstraintsIfNeeded]; - [self animateAllTicksIn:YES]; - [self popTickIfNeededFromTouch:touch]; + if (_customTicksEnabled && _ticks && [_ticks count] > 0) { + // ?? - TODO: Write this part. + } + else { + // Update the width + [self updateLeftTickConstraintsIfNeeded]; + [self animateAllTicksIn:YES]; + [self popTickIfNeededFromTouch:touch]; + } return [super beginTrackingWithTouch:touch withEvent:event]; } @@ -798,6 +932,11 @@ - (CGFloat)segmentWidth return floorf(CGRectGetWidth(trackRect) / self.sectionCount); } +- (CGFloat)trackWidth { + CGRect trackRect = [self trackRectForBounds:self.bounds]; + return floorf(CGRectGetWidth(trackRect)); +} + - (NSInteger)middleTickIndex { return floor(self.tickViews.count / 2); From d9bb120b62cec7532bd1ed8e20c4f58372d3d3be Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Sun, 18 Feb 2018 15:20:12 -0700 Subject: [PATCH 03/33] Cleanup of unused code. Finalizing custom tick spacing and animation setup. Add var to toggle tick transparency. --- Library/HUMSlider.h | 3 + Library/HUMSlider.m | 210 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 173 insertions(+), 40 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index bd02c09..5ddd41b 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -40,6 +40,9 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { ///How many points the tick popping should be adjusted for a custom thumbnail image to account for any space at the top (for example, to balance out a custom shadow). @property (nonatomic) CGFloat pointAdjustmentForCustomThumb; +//Fade the ticks out to transparent when the user is not actively moving the slider. +@property (nonatomic) BOOL enableTicksTransparencyOnIdle; + #pragma mark - Images ///The color to use as the fully-saturated color on both sides. Defaults to red. diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index e5a87f1..81b319e 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -8,6 +8,8 @@ #import "HUMSlider.h" +#pragma mark - warning TODO: Tick position isn't quite right on... I think we need to subtrack the tick width. + // Animation Durations static NSTimeInterval const HUMTickAlphaDuration = 0.20; static NSTimeInterval const HUMTickMovementDuration = 0.5; @@ -38,8 +40,14 @@ @interface HUMSlider () @property (nonatomic) NSArray *tickViews; @property (nonatomic) NSArray *allTickBottomConstraints; -@property (nonatomic) NSArray *leftTickRightConstraints; -@property (nonatomic) NSArray *rightTickLeftConstraints; + +//Constraint storage for evenly spaced tick constraints. +@property (nonatomic) NSArray *leftTickRightConstraints; //Confusing name.. what is a left tick? Left of middle? +@property (nonatomic) NSArray *rightTickLeftConstraints; //Confusing name.. what is a right tick? Right of middle? + +//Constraint storage for dynamically spaced tick constraints. +@property (nonatomic) NSArray *tickLeftConstraints; +@property (nonatomic) NSArray *tickRightConstraints; @property (nonatomic) UIImage *leftTemplate; @property (nonatomic) UIImage *rightTemplate; @@ -55,13 +63,16 @@ @interface HUMSlider () @end -@implementation HUMSlider +@implementation HUMSlider { + NSMutableArray *positionDiffs; +} #pragma mark - Init - (void)commonInit { - self.customTicksEnabled = true; + self.customTicksEnabled = true; //default to true + self.enableTicksTransparencyOnIdle = false; // keep ticks at all times. // Set default values. self.sectionCount = 9; @@ -130,6 +141,8 @@ - (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView { } if (refreshView) { + //TODO Fix this shit. +#pragma mark - warning - refresh this view. [self setupTicks]; } } @@ -157,26 +170,44 @@ - (void)refreshView { - (void)setupTicks { -// NSUInteger count = _ticks ? [_ticks count] : self.sectionCount; -// NSMutableArray *tickBuilder = [NSMutableArray array]; -// for (NSInteger i = 0; i < count; i++) { -// UIView *tick = [[UIView alloc] init]; -// tick.backgroundColor = self.tickColor; -// tick.alpha = 0; -// tick.translatesAutoresizingMaskIntoConstraints = NO; -// [self addSubview:tick]; -// [self sendSubviewToBack:tick]; -// [tickBuilder addObject:tick]; -// } -// -// self.tickViews = tickBuilder; - if (_customTicksEnabled && _ticks && [_ticks count] > 0) { + if ([self areCustomTicksSetupAndNonNull]) { + [self cleanupAfterEvenlySpacedTicks]; [self setupCustomTickViews]; [self setupTicksAutoLayoutCustomWidths]; + if (!_enableTicksTransparencyOnIdle) { + [self animateAllTicksInCustomWidths:YES]; + } } else { + [self cleanupAfterCustomSpacedTicks]; [self setupSpacedTickViews]; [self setupTicksAutolayout]; + if (!_enableTicksTransparencyOnIdle) { + [self animateAllTicksIn:YES]; + } + } + + +} + +- (void)cleanupAfterEvenlySpacedTicks { + self.tickViews = [NSArray new]; // Make sure these get re-initialized + [self clearLayoutConstraintList:_leftTickRightConstraints]; + [self clearLayoutConstraintList:_rightTickLeftConstraints]; + [self clearLayoutConstraintList:_allTickBottomConstraints]; +} + +- (void)cleanupAfterCustomSpacedTicks { + self.tickViews = [NSArray new]; // Make sure these get re-initialized + [self clearLayoutConstraintList:_tickLeftConstraints]; + [self clearLayoutConstraintList:_tickRightConstraints]; + [self clearLayoutConstraintList:_allTickBottomConstraints]; +} + +// Disassociate all of the NSLayoutConstraints in the list from the parent view. +- (void)clearLayoutConstraintList:(NSArray*)list { + for (NSLayoutConstraint *constraint in list) { + [self removeConstraint:constraint]; } } @@ -185,9 +216,14 @@ - (void)setupSpacedTickViews { } - (void)setupCustomTickViews { + NSLog(@"Setting up Custom tick views for %d custom ticks.", (int)[_ticks count]); [self createAndAddBlankTickViewsWithCount:(int)[_ticks count]]; } +- (bool)areCustomTicksSetupAndNonNull { + return (_customTicksEnabled && _ticks && [_ticks count] > 0); +} + - (void)createAndAddBlankTickViewsWithCount:(int)count { NSMutableArray *tickBuilder = [NSMutableArray array]; for (NSInteger i = 0; i < count; i++) { @@ -208,25 +244,35 @@ - (UIView*)setupCommonTickViewAnddAddToSubview { return tick; } +// Calculate the distance differences between each tick according to the pixel width of the slider. +// Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. +- (void)calculateTickDifferences { + positionDiffs = [NSMutableArray new]; + + int tickCount = (int)[self.tickViews count]; + for (NSInteger i = 0; i <= tickCount; i++) { + double currentItem = i == tickCount ? [self trackWidth] : ((Tick*)self.ticks[i]).position; + double previousTime = i == 0 ? 0 : ((Tick*)self.ticks[i - 1]).position; + double zeroToOnePercentage = currentItem - previousTime; + double distanceDiff = zeroToOnePercentage * [self trackWidth] - 3; + distanceDiff = floor(distanceDiff); + [positionDiffs insertObject:[NSNumber numberWithDouble: distanceDiff - HUMTickWidth] atIndex:(i)]; + } + NSLog(@"Calculated %d position differentials", (int)[positionDiffs count]); +} + #pragma mark Autolayout -#warning - this is called with zero tickViews and zero elements in _ticks - (void)setupTicksAutoLayoutCustomWidths { //Store the left, right and bottom constraints for some reason NSMutableArray *bottoms = [NSMutableArray array]; NSMutableArray *lefts = [NSMutableArray array]; NSMutableArray *rights = [NSMutableArray array]; - //Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. - NSMutableArray *positionDiffs = [NSMutableArray new]; int tickCount = (int)[self.tickViews count]; - for (NSInteger i = 0; i <= tickCount; i++) { - double currentItem = i == tickCount ? [self trackWidth] : ((Tick*)self.ticks[i]).position; - double previousTime = i == 0 ? 0 : ((Tick*)self.ticks[i - 1]).position; - double zeroToOnePercentage = currentItem - previousTime; - double distanceDiff = zeroToOnePercentage * [self trackWidth]; - [positionDiffs insertObject:[NSNumber numberWithDouble: distanceDiff] atIndex:(i)]; - } + + //Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. + [self calculateTickDifferences]; //This is the new code to start at the first one. for (NSInteger i = 0; i < [self.tickViews count]; i++) { @@ -296,10 +342,13 @@ - (void)setupTicksAutoLayoutCustomWidths { [rights addObject:right]; } } + + NSLog(@"Created %d custom lefts, %d custom rights, and %d custom bottoms", (int)[lefts count], (int)[rights count], (int)[bottoms count]); self.allTickBottomConstraints = bottoms; - self.leftTickRightConstraints = lefts; - self.rightTickLeftConstraints = rights; + + self.tickLeftConstraints = lefts; + self.tickRightConstraints = rights; [self layoutIfNeeded]; } @@ -345,11 +394,6 @@ - (void)setupTicksAutolayout [self pinTickWidthAndHeight:nextToRight]; NSLayoutConstraint *rightBottom = [self pinTickBottom:nextToRight]; [bottoms addObject:rightBottom]; -#warning - clean up. -// int multiplier = 1; -// if (i == 3) { -// multiplier = 1; -// } // Pin the right of the next leftwards tick to the previous leftwards tick NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:nextToLeft @@ -460,6 +504,8 @@ - (void)sliderAdjusted { CGFloat halfValue = (self.minimumValue + self.maximumValue) / 2.0f; + //TODO: Do we need to do anything special here? What does this do? + if (self.value > halfValue) { self.rightSaturatedImageView.alpha = (self.value - halfValue) / halfValue; self.leftSaturatedImageView.alpha = 0; @@ -579,6 +625,7 @@ - (void)layoutSubviews [self updateLeftTickConstraintsIfNeeded]; } +// First method that is called when animating ticks in. - (void)updateLeftTickConstraintsIfNeeded { NSLayoutConstraint *firstLeft = self.leftTickRightConstraints.firstObject; @@ -595,6 +642,34 @@ - (void)updateLeftTickConstraintsIfNeeded } // else good to go. } +- (void)updateCustomTickConstraintsIfNeeded +{ + int tickCount = (int)[self.tickViews count]; + + // Calculate position differences if necessary. + if (!positionDiffs || [positionDiffs count] != tickCount + 1) { + [self calculateTickDifferences]; + } + + NSLayoutConstraint *firstLeft = self.tickLeftConstraints.firstObject; // special case - pin left of view to left-most tick. + NSLayoutConstraint *lastRight = self.tickRightConstraints.lastObject; // special case - pin right of view to right-most tick. + + if (firstLeft.constant != ((NSNumber*)positionDiffs.firstObject).doubleValue) { + firstLeft.constant = ((NSNumber*)positionDiffs.firstObject).doubleValue; + lastRight.constant = ((NSNumber*)positionDiffs.lastObject).doubleValue; + + //This is the new code to start at the first one. + for (NSInteger i = 1; i < tickCount; i++) { + NSLayoutConstraint *leftConstraint = _tickLeftConstraints[i]; + NSLayoutConstraint *rightConstraint = _tickRightConstraints[i]; + leftConstraint.constant = ((NSNumber*)positionDiffs[i]).doubleValue; + rightConstraint.constant = ((NSNumber*)positionDiffs[i+1]).doubleValue; // we have one more position diff than ticks. + } + + [self layoutIfNeeded]; + } +} + #pragma mark - Overridden Setters - (void)setValue:(float)value @@ -716,6 +791,9 @@ - (UIColor *)desaturatedColorForSide:(HUMSliderSide)side - (UIImageView *)imageViewForSide:(HUMSliderSide)side saturated:(BOOL)saturated { + //TODO: Figure out what this is used for and update it. +#pragma mark - warning, see the thing above. + switch (side) { case HUMSliderSideLeft: if (saturated) { @@ -749,8 +827,11 @@ - (void)setTickColor:(UIColor *)tickColor - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { - if (_customTicksEnabled && _ticks && [_ticks count] > 0) { - // ?? - TODO: Write this part. + if ([self areCustomTicksSetupAndNonNull]) { + + [self updateCustomTickConstraintsIfNeeded]; + [self animateAllTicksInCustomWidths:YES]; + [self popTickIfNeededFromTouch:touch]; } else { // Update the width @@ -764,7 +845,13 @@ - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event - (void)animateTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { + if (_customTicksEnabled) { + #pragma warning - we need to redo this too. sad days. + return; + } + UIView *tick = self.tickViews[tickIndex]; + CGFloat startSegmentX = (tickIndex * self.segmentWidth) + self.trackXOrigin; CGFloat endSegmentX = startSegmentX + self.segmentWidth; @@ -793,6 +880,9 @@ - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event - (void)popTickIfNeededFromTouch:(UITouch *)touch { +#pragma mark - Warning - update this method for custom tick widths. + //TODO: This method needs to be updated for the custom tick widths. + // Figure out where the hell the thumb is. CGRect trackRect = [self trackRectForBounds:self.bounds]; CGRect thumbRect = [self thumbRectForBounds:self.bounds @@ -824,20 +914,60 @@ - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - [self returnPosition]; + [self returnPosition]; //TODO: WTF does return position do? This just calls the animage method again... [super touchesEnded:touches withEvent:event]; } - (void)returnPosition { - [self animateAllTicksIn:NO]; + //TODO: This is our guy! + if ([self areCustomTicksSetupAndNonNull]) { + [self animateAllTicksInCustomWidths:NO]; + } + else { + [self animateAllTicksIn:NO]; + } +} + +// To Remove - my method for custom widths +- (void)animateAllTicksInCustomWidths:(BOOL)inPosition +{ + assert([self areCustomTicksSetupAndNonNull] == true); + + CGFloat origin; + CGFloat alpha; + + if (inPosition) { // Ticks are out, coming in //TODO: Re-use this code. + alpha = 1; + origin = [self tickInNotPoppedPositon]; + } else { // Ticks are in, coming out. + alpha = _enableTicksTransparencyOnIdle ? 0 : 1; // Transparent if setting is enabed. + origin = [self tickOutPosition]; + } + + [UIView animateWithDuration:self.tickAlphaAnimationDuration + animations:^{ + for (UIView *tick in self.tickViews) { + tick.alpha = alpha; + } + } completion:nil]; + + for (NSInteger i = 0; i < [self.tickViews count]; i++) { + + [self animateTickAtIndex:i + toYOrigin:origin + withDuration:self.tickMovementAnimationDuration + delay:self.nextTickAnimationDelay * i]; + } } #pragma mark - Tick Animation - (void)animateAllTicksIn:(BOOL)inPosition { + assert([self areCustomTicksSetupAndNonNull] == false); + CGFloat origin; CGFloat alpha; @@ -845,7 +975,7 @@ - (void)animateAllTicksIn:(BOOL)inPosition alpha = 1; origin = [self tickInNotPoppedPositon]; } else { // Ticks are in, coming out. - alpha = 0; + alpha = _enableTicksTransparencyOnIdle ? 0 : 1; origin = [self tickOutPosition]; } From d649c67719bd824324c80b94877ef4654058b30d Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Mon, 19 Feb 2018 17:11:05 -0700 Subject: [PATCH 04/33] Trying another approach. --- Library/HUMSlider.h | 4 +- Library/HUMSlider.m | 309 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 272 insertions(+), 41 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index 5ddd41b..b6d39cb 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -73,7 +73,6 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { /** * Inserts a tick at a position. - * * @param tick. The tick with the set position between 0 and 1 */ - (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView; @@ -85,8 +84,7 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { /** * Removes the tick at the given index. . - * - * @param tick. The tick with the set position between 0 and 1 + * @param index. The tick Index with the set position between 0 and 1 */ - (void)removeTickAtIndex:(uint)index; diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 81b319e..b81167b 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -8,8 +8,6 @@ #import "HUMSlider.h" -#pragma mark - warning TODO: Tick position isn't quite right on... I think we need to subtrack the tick width. - // Animation Durations static NSTimeInterval const HUMTickAlphaDuration = 0.20; static NSTimeInterval const HUMTickMovementDuration = 0.5; @@ -64,13 +62,18 @@ @interface HUMSlider () @end @implementation HUMSlider { - NSMutableArray *positionDiffs; + NSMutableArray *positionDiffs; //For custom tick views - diff between each tick in slider px. + NSMutableArray *fromLeftPositionDiffs; //Distance from left in px for each custom tick. + + double thumbImageWidth; } #pragma mark - Init - (void)commonInit { + [self thumbImageWidth]; // Lazy init of initial calc of thumb image width. + self.customTicksEnabled = true; //default to true self.enableTicksTransparencyOnIdle = false; // keep ticks at all times. @@ -125,11 +128,13 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder #pragma mark - Ticks +#warning - Create method to add all ticks. + - (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView { if ([self.ticks count] == 0) { [self.ticks addObject:tick]; } - else { + else { // Sorted-ly add the tick in the right sorted order. unsigned long index = [self.ticks count]; for (Tick *tick_itr in [self.ticks reverseObjectEnumerator]) { if (tick.position >= tick_itr.position) { @@ -141,9 +146,7 @@ - (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView { } if (refreshView) { - //TODO Fix this shit. -#pragma mark - warning - refresh this view. - [self setupTicks]; + [self setupTickViews]; } } @@ -151,7 +154,7 @@ - (void)removeTickAtIndex:(uint)index { [_ticks removeObjectAtIndex:index]; } -- (void)nukeOldTicks +- (void)nukeOldTickViews { for (UIView *tick in self.tickViews) { [tick removeFromSuperview]; @@ -165,39 +168,37 @@ - (void)nukeOldTicks } - (void)refreshView { - [self setupTicks]; + [self setupTickViews]; } -- (void)setupTicks +- (void)setupTickViews { if ([self areCustomTicksSetupAndNonNull]) { - [self cleanupAfterEvenlySpacedTicks]; + [self cleanupConstraintsAfterEvenlySpacedTicks]; [self setupCustomTickViews]; - [self setupTicksAutoLayoutCustomWidths]; + [self setupTicksAutoLayoutCustomWidths2]; if (!_enableTicksTransparencyOnIdle) { [self animateAllTicksInCustomWidths:YES]; } } else { - [self cleanupAfterCustomSpacedTicks]; + [self cleanupConstraintsAfterCustomSpacedTicks]; [self setupSpacedTickViews]; [self setupTicksAutolayout]; if (!_enableTicksTransparencyOnIdle) { [self animateAllTicksIn:YES]; } } - - } -- (void)cleanupAfterEvenlySpacedTicks { +- (void)cleanupConstraintsAfterEvenlySpacedTicks { self.tickViews = [NSArray new]; // Make sure these get re-initialized [self clearLayoutConstraintList:_leftTickRightConstraints]; [self clearLayoutConstraintList:_rightTickLeftConstraints]; [self clearLayoutConstraintList:_allTickBottomConstraints]; } -- (void)cleanupAfterCustomSpacedTicks { +- (void)cleanupConstraintsAfterCustomSpacedTicks { self.tickViews = [NSArray new]; // Make sure these get re-initialized [self clearLayoutConstraintList:_tickLeftConstraints]; [self clearLayoutConstraintList:_tickRightConstraints]; @@ -227,14 +228,14 @@ - (bool)areCustomTicksSetupAndNonNull { - (void)createAndAddBlankTickViewsWithCount:(int)count { NSMutableArray *tickBuilder = [NSMutableArray array]; for (NSInteger i = 0; i < count; i++) { - UIView *tick = [self setupCommonTickViewAnddAddToSubview]; + UIView *tick = [self setupCommonTickViewAndAddToSubview]; [tickBuilder addObject:tick]; } self.tickViews = tickBuilder; } -- (UIView*)setupCommonTickViewAnddAddToSubview { +- (UIView*)setupCommonTickViewAndAddToSubview { UIView *tick = [[UIView alloc] init]; tick.backgroundColor = self.tickColor; tick.alpha = 0; @@ -247,16 +248,79 @@ - (UIView*)setupCommonTickViewAnddAddToSubview { // Calculate the distance differences between each tick according to the pixel width of the slider. // Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. - (void)calculateTickDifferences { - positionDiffs = [NSMutableArray new]; + positionDiffs = [NSMutableArray new]; // All tick positions (in pixels) relative to the next tick on either side. + fromLeftPositionDiffs = [NSMutableArray new]; // All tick positions (in horizontal pixels) from the far left of the slider view. - int tickCount = (int)[self.tickViews count]; +// double thumbSliderWidth = [self thumbImageWidth]; +// double trackWidth = [self thumbImageWidth]; +// double trackXOrigin = [self trackXOrigin]; + + // - [self thumbImageWidth] + //double sliderBasedCenterTrackWidth = [self trackWidth]; // Subtract the slider Diameter, the center of it is the actual start. + + //CGRect trackRect = [slider trackRectForBounds:slider.bounds]; + + double trackWidth = [self trackWidth]; // self.bounds.size.width //TODO: Track Width Bug (see bottom method.) + //double trackWidth2 = self.bounds.size.width; + double sliderThumbDiameter = [self thumbImageWidth]; + + double sliderBasedCenterTrackWidth = trackWidth - (sliderThumbDiameter); // times two because it isn't from origin? + + //TODO: Try this. + //double sliderBasedCenterTrackWidth = self.bounds.size.width - (tickCount * HUMTickWidth); // times two because it isn't from origin? + + //double zeroToOnePercentangeWidthWithoutThumbImage = sliderBasedCenterTrackWidth / self.bounds.size.width; + + //double zeroToOnePercentangeWidthWithoutThumbImage = (sliderBasedCenterTrackWidth / [self trackWidth]) ; + + //double zeroToOnePercentangeWidthWithoutThumbImage = (sliderBasedCenterTrackWidth / trackWidth) ; + + //double fromCenter = zeroToOnePercentangeWidthWithoutThumbImage - 0.5; + + int tickCount = (int)[_ticks count]; //Have Tick views been updated? + + double fromLeftRollingAppender = 0; //TODO: Start at OriginX? for (NSInteger i = 0; i <= tickCount; i++) { - double currentItem = i == tickCount ? [self trackWidth] : ((Tick*)self.ticks[i]).position; - double previousTime = i == 0 ? 0 : ((Tick*)self.ticks[i - 1]).position; - double zeroToOnePercentage = currentItem - previousTime; - double distanceDiff = zeroToOnePercentage * [self trackWidth] - 3; - distanceDiff = floor(distanceDiff); - [positionDiffs insertObject:[NSNumber numberWithDouble: distanceDiff - HUMTickWidth] atIndex:(i)]; + double currentItem = i == tickCount ? 1 : ((Tick*)self.ticks[i]).position; // zero to one percentage. + double previousItem = i == 0 ? 0 : ((Tick*)self.ticks[i - 1]).position; // zero to one percentage + + double currItemMultValue = currentItem - 0.5; + double prevItemMultValue = previousItem - 0.5; + + double zeroToOnePercentage = currentItem - previousItem; + //double zeroToOnePercentage2 = (currItemMultValue - prevItemMultValue); // * zeroToOnePercentangeWidthWithoutThumbImage; + //double distanceDiff = (zeroToOnePercentage * sliderBasedCenterTrackWidth) - HUMTickWidth; // - HUMTickWidth + double distanceDiff = (zeroToOnePercentage * trackWidth); // - HUMTickWidth + //double distanceDiff = (zeroToOnePercentage2 * [self trackWidth]) - HUMTickWidth; + + +// double distanceDiff2 = ((currItemMultValue * sliderBasedCenterTrackWidth) - (prevItemMultValue * sliderBasedCenterTrackWidth) - HUMTickWidth); +// //double distanceDiff2 = ((currentItem * sliderBasedCenterTrackWidth) - (previousTime * sliderBasedCenterTrackWidth)) - HUMTickWidth; +// if (floor(distanceDiff) != floor(distanceDiff2)) { +// bool shit = true; +// } +// else { +// bool justFine = true; +// //distanceDiff -= HUMTickWidth; +// } + //if (i == 0) { + //distanceDiff += [self trackXOrigin] + (HUMTickWidth / 2.0); //Half of thumb image width. + //distanceDiff += (sliderThumbDiameter / 2) - (HUMTickWidth / 2.0); // - [self trackXOrigin]; //[self trackXOrigin] + + //} + //else if (i == tickCount) { + //distanceDiff += (sliderThumbDiameter / 2) - (HUMTickWidth / 2.0); // - [self trackXOrigin]; + //} + + //Far left and far right tick constraints need to be adjusted in towards the center of the slider by half of the thumb image radius. + if (i == 0 || i == tickCount) { + //distanceDiff += [self thumbImageWidth] / 4;// - HUMTickWidth; + //distanceDiff += HUMTickWidth; + //distanceDiff += [self trackXOrigin]; + } + //distanceDiff = floor(distanceDiff) - HUMTickWidth; //TODO: OriginX? + [positionDiffs insertObject:[NSNumber numberWithDouble: distanceDiff] atIndex:(i)]; + fromLeftRollingAppender += distanceDiff; + [fromLeftPositionDiffs insertObject:[NSNumber numberWithDouble: fromLeftRollingAppender] atIndex:(i)]; } NSLog(@"Calculated %d position differentials", (int)[positionDiffs count]); } @@ -264,6 +328,9 @@ - (void)calculateTickDifferences { #pragma mark Autolayout - (void)setupTicksAutoLayoutCustomWidths { + + assert([self areCustomTicksSetupAndNonNull]); + //Store the left, right and bottom constraints for some reason NSMutableArray *bottoms = [NSMutableArray array]; NSMutableArray *lefts = [NSMutableArray array]; @@ -298,6 +365,7 @@ - (void)setupTicksAutoLayoutCustomWidths { attribute:NSLayoutAttributeLeft multiplier:1 constant:diff]; + [farLeft setPriority:UILayoutPriorityDefaultHigh]; [self addConstraint:farLeft]; [lefts addObject:farLeft]; } @@ -325,6 +393,7 @@ - (void)setupTicksAutoLayoutCustomWidths { attribute:NSLayoutAttributeRight multiplier:1 constant:diff]; + [farRight setPriority:UILayoutPriorityDefaultHigh]; [self addConstraint:farRight]; [rights addObject:farRight]; } @@ -353,8 +422,75 @@ - (void)setupTicksAutoLayoutCustomWidths { [self layoutIfNeeded]; } +- (void)setupTicksAutoLayoutCustomWidths2 { + + assert([self areCustomTicksSetupAndNonNull]); + + //Store the left, right and bottom constraints for some reason + NSMutableArray *bottoms = [NSMutableArray array]; + NSMutableArray *lefts = [NSMutableArray array]; + NSMutableArray *rights = [NSMutableArray array]; + + int tickCount = (int)[self.tickViews count]; + + //Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. + [self calculateTickDifferences]; + + //This is the new code to start at the first one. + for (NSInteger i = 0; i < [self.tickViews count]; i++) { + bool isFirst = i == 0 ? true : false; + bool isLast = i == tickCount - 1 ? true : false; + + UIView *currentItem = self.tickViews[i]; + UIView *previousItem = isFirst ? NULL : self.tickViews[i - 1]; + UIView *nextItem = isLast ? NULL : self.tickViews[i + 1]; + + NSLayoutConstraint *bottomConstraint = [self pinTickBottom:currentItem]; + [self addConstraint:bottomConstraint]; + [bottoms insertObject:bottomConstraint atIndex:i]; + [self pinTickWidthAndHeight:currentItem]; + + CGFloat diff = [fromLeftPositionDiffs[i] doubleValue]; + // Pin the first tick to the left of the view. + NSLayoutConstraint *farLeft = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeLeft + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeLeft + multiplier:1 + constant:diff]; + [farLeft setPriority:UILayoutPriorityDefaultHigh]; + [self addConstraint:farLeft]; + [lefts addObject:farLeft]; + + diff = [self trackWidth] - diff; + // Pin the first tick to the left of the view. + NSLayoutConstraint *farRight = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeRight + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeRight + multiplier:1 + constant:diff]; + [farRight setPriority:UILayoutPriorityDefaultHigh]; + [self addConstraint:farRight]; + [rights addObject:farRight]; + } + + NSLog(@"Created %d custom lefts, %d custom rights, and %d custom bottoms", (int)[lefts count], (int)[rights count], (int)[bottoms count]); + + self.allTickBottomConstraints = bottoms; + + self.tickLeftConstraints = lefts; + self.tickRightConstraints = rights; + + [self layoutIfNeeded]; +} + - (void)setupTicksAutolayout { + assert(![self areCustomTicksSetupAndNonNull]); + NSMutableArray *bottoms = [NSMutableArray array]; NSMutableArray *lefts = [NSMutableArray array]; NSMutableArray *rights = [NSMutableArray array]; @@ -622,12 +758,20 @@ - (void)pinView1Center:(UIView *)view1 toView2Center:(UIView *)view2 - (void)layoutSubviews { [super layoutSubviews]; - [self updateLeftTickConstraintsIfNeeded]; + if ([self areCustomTicksSetupAndNonNull]) { + [self updateCustomTickConstraintsIfNeeded2]; + } + else { + [self updateLeftTickConstraintsIfNeeded]; + } + } // First method that is called when animating ticks in. - (void)updateLeftTickConstraintsIfNeeded { + assert(![self areCustomTicksSetupAndNonNull]); + NSLayoutConstraint *firstLeft = self.leftTickRightConstraints.firstObject; if (firstLeft.constant != (self.segmentWidth - HUMTickWidth)) { @@ -644,9 +788,12 @@ - (void)updateLeftTickConstraintsIfNeeded - (void)updateCustomTickConstraintsIfNeeded { + assert([self areCustomTicksSetupAndNonNull]); + int tickCount = (int)[self.tickViews count]; // Calculate position differences if necessary. + // TODO Cleanup if (!positionDiffs || [positionDiffs count] != tickCount + 1) { [self calculateTickDifferences]; } @@ -654,7 +801,7 @@ - (void)updateCustomTickConstraintsIfNeeded NSLayoutConstraint *firstLeft = self.tickLeftConstraints.firstObject; // special case - pin left of view to left-most tick. NSLayoutConstraint *lastRight = self.tickRightConstraints.lastObject; // special case - pin right of view to right-most tick. - if (firstLeft.constant != ((NSNumber*)positionDiffs.firstObject).doubleValue) { + //if (firstLeft.constant != ((NSNumber*)positionDiffs.firstObject).doubleValue) { firstLeft.constant = ((NSNumber*)positionDiffs.firstObject).doubleValue; lastRight.constant = ((NSNumber*)positionDiffs.lastObject).doubleValue; @@ -667,7 +814,39 @@ - (void)updateCustomTickConstraintsIfNeeded } [self layoutIfNeeded]; + //} +} + +- (void)updateCustomTickConstraintsIfNeeded2 +{ + assert([self areCustomTicksSetupAndNonNull]); + + int tickCount = (int)[self.tickViews count]; + + // Calculate position differences if necessary. + // TODO Cleanup + if (!positionDiffs || [positionDiffs count] != tickCount + 1) { + [self calculateTickDifferences]; } + + NSLayoutConstraint *firstLeft = self.tickLeftConstraints.firstObject; // special case - pin left of view to left-most tick. + NSLayoutConstraint *lastRight = self.tickRightConstraints.lastObject; // special case - pin right of view to right-most tick. + + //if (firstLeft.constant != ((NSNumber*)positionDiffs.firstObject).doubleValue) { + firstLeft.constant = ((NSNumber*)positionDiffs.firstObject).doubleValue; + lastRight.constant = ((NSNumber*)positionDiffs.lastObject).doubleValue; + + //This is the new code to start at the first one. + for (NSInteger i = 1; i < tickCount; i++) { + NSLayoutConstraint *leftConstraint = _tickLeftConstraints[i]; + NSLayoutConstraint *rightConstraint = _tickRightConstraints[i]; + double fromLeft = ((NSNumber*)fromLeftPositionDiffs[i]).doubleValue; + leftConstraint.constant = fromLeft; + rightConstraint.constant = [self trackWidth] - fromLeft; // we have one more position diff than ticks. + } + + [self layoutIfNeeded]; + //} } #pragma mark - Overridden Setters @@ -685,8 +864,8 @@ - (void)setSectionCount:(NSUInteger)sectionCount _sectionCount = sectionCount; - [self nukeOldTicks]; - [self setupTicks]; + [self nukeOldTickViews]; + [self setupTickViews]; } - (void)setMinimumValueImage:(UIImage *)minimumValueImage @@ -843,13 +1022,43 @@ - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event return [super beginTrackingWithTouch:touch withEvent:event]; } -- (void)animateTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX +// TODO: Hook this up +- (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { - if (_customTicksEnabled) { - #pragma warning - we need to redo this too. sad days. - return; + assert ([self areCustomTicksSetupAndNonNull]); + + UIView *tick = self.tickViews[tickIndex]; + + NSLog(@" Track X Origin: %f", self.trackXOrigin); + + double distanceFromLeft = ((NSNumber*)fromLeftPositionDiffs[tickIndex]).doubleValue; + + double thumbSliderRadius = [self thumbImageWidth] / 2; + + CGFloat startSegmentX = distanceFromLeft - thumbSliderRadius; //TODO: Make a constant for the interval - from AdjustedThumbSlider subclass. + CGFloat endSegmentX = distanceFromLeft + thumbSliderRadius; + + CGFloat desiredOrigin; + if (startSegmentX <= touchX && endSegmentX > touchX) { + // Pop up. + desiredOrigin = [self tickPoppedPosition]; + } else { + // Bring down. + desiredOrigin = [self tickInNotPoppedPositon]; } + if (CGRectGetMinY(tick.frame) != desiredOrigin) { + [self animateTickAtIndex:tickIndex + toYOrigin:desiredOrigin + withDuration:self.tickMovementAnimationDuration + delay:0]; + } // else tick is already where it needs to be. +} + +- (void)animateTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX +{ + assert (![self areCustomTicksSetupAndNonNull]); + UIView *tick = self.tickViews[tickIndex]; CGFloat startSegmentX = (tickIndex * self.segmentWidth) + self.trackXOrigin; @@ -888,11 +1097,18 @@ - (void)popTickIfNeededFromTouch:(UITouch *)touch CGRect thumbRect = [self thumbRectForBounds:self.bounds trackRect:trackRect value:self.value]; + +#warning - there may be an issue calculating the slider location. CGFloat sliderLoc = CGRectGetMidX(thumbRect); // Animate tick based on the thumb location for (NSInteger i = 0; i < self.tickViews.count; i++) { - [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; + if ([self areCustomTicksSetupAndNonNull]) { + [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; + } + else { + [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; + } } } @@ -938,7 +1154,7 @@ - (void)animateAllTicksInCustomWidths:(BOOL)inPosition CGFloat origin; CGFloat alpha; - if (inPosition) { // Ticks are out, coming in //TODO: Re-use this code. + if (inPosition) { // Ticks are out, coming in alpha = 1; origin = [self tickInNotPoppedPositon]; } else { // Ticks are in, coming out. @@ -1064,7 +1280,8 @@ - (CGFloat)segmentWidth - (CGFloat)trackWidth { CGRect trackRect = [self trackRectForBounds:self.bounds]; - return floorf(CGRectGetWidth(trackRect)); + return CGRectGetWidth(trackRect); + //return floorf(CGRectGetWidth(trackRect)); } - (NSInteger)middleTickIndex @@ -1103,4 +1320,20 @@ - (CGFloat)tickPoppedPosition return [self tickInNotPoppedPositon] - [self tickInToPoppedDifferential] + self.pointAdjustmentForCustomThumb; } +- (double)thumbImageWidth // default thumb image is 30 px, +{ + // Won't fail to compute the thumb image width unless its width is 0; + if (!thumbImageWidth || thumbImageWidth == 0) { + + double thumbImageWidthFromSetImage = self.currentThumbImage.size.width; + if (!thumbImageWidthFromSetImage || thumbImageWidthFromSetImage == 0) { + thumbImageWidth = 30; //Guess and check default value for thumb image on UISlider. + } + else { + thumbImageWidth = thumbImageWidthFromSetImage; + } + } + return thumbImageWidth; +} + @end From adce66571c3367d187cd3bc77dae181969e64a5b Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 18:56:50 -0700 Subject: [PATCH 05/33] tick spacing is working --- Library/HUMSlider.h | 3 + Library/HUMSlider.m | 442 ++++++++++++-------------------------------- 2 files changed, 117 insertions(+), 328 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index b6d39cb..7157b52 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -116,4 +116,7 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { */ - (UIColor *)desaturatedColorForSide:(HUMSliderSide)side; +// TODO: Update the tick heights. +- (void)updateTickHeights; + @end diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index b81167b..7a46146 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -44,8 +44,7 @@ @interface HUMSlider () @property (nonatomic) NSArray *rightTickLeftConstraints; //Confusing name.. what is a right tick? Right of middle? //Constraint storage for dynamically spaced tick constraints. -@property (nonatomic) NSArray *tickLeftConstraints; -@property (nonatomic) NSArray *tickRightConstraints; +@property (nonatomic) NSArray *middleTickConstraints; @property (nonatomic) UIImage *leftTemplate; @property (nonatomic) UIImage *rightTemplate; @@ -62,16 +61,19 @@ @interface HUMSlider () @end @implementation HUMSlider { - NSMutableArray *positionDiffs; //For custom tick views - diff between each tick in slider px. - NSMutableArray *fromLeftPositionDiffs; //Distance from left in px for each custom tick. - - double thumbImageWidth; +#warning - clean this up +// NSMutableArray *positionDiffs; //For custom tick views - diff between each tick in slider px. +// NSMutableArray *fromLeftPositionDiffs; //Distance from left in px for each custom tick. +// + CGFloat thumbImageWidth; // Reference to last computed thumb width. + CGRect trackRect; // store the track width from the layoutSubviews. } #pragma mark - Init - (void)commonInit { + trackRect = CGRectZero; [self thumbImageWidth]; // Lazy init of initial calc of thumb image width. self.customTicksEnabled = true; //default to true @@ -130,7 +132,9 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder #warning - Create method to add all ticks. -- (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView { +- (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { +#warning - When doing the constraint from center x, the ticks do not need to be in order anymore + if ([self.ticks count] == 0) { [self.ticks addObject:tick]; } @@ -176,7 +180,7 @@ - (void)setupTickViews if ([self areCustomTicksSetupAndNonNull]) { [self cleanupConstraintsAfterEvenlySpacedTicks]; [self setupCustomTickViews]; - [self setupTicksAutoLayoutCustomWidths2]; + [self setupTicksAutoLayoutCustomWidths]; if (!_enableTicksTransparencyOnIdle) { [self animateAllTicksInCustomWidths:YES]; } @@ -200,15 +204,16 @@ - (void)cleanupConstraintsAfterEvenlySpacedTicks { - (void)cleanupConstraintsAfterCustomSpacedTicks { self.tickViews = [NSArray new]; // Make sure these get re-initialized - [self clearLayoutConstraintList:_tickLeftConstraints]; - [self clearLayoutConstraintList:_tickRightConstraints]; - [self clearLayoutConstraintList:_allTickBottomConstraints]; + [self clearLayoutConstraintList:self.middleTickConstraints]; + [self clearLayoutConstraintList:self.allTickBottomConstraints]; } // Disassociate all of the NSLayoutConstraints in the list from the parent view. - (void)clearLayoutConstraintList:(NSArray*)list { - for (NSLayoutConstraint *constraint in list) { - [self removeConstraint:constraint]; + if (list) { + for (NSLayoutConstraint *constraint in list) { + [self removeConstraint:constraint]; + } } } @@ -217,12 +222,11 @@ - (void)setupSpacedTickViews { } - (void)setupCustomTickViews { - NSLog(@"Setting up Custom tick views for %d custom ticks.", (int)[_ticks count]); - [self createAndAddBlankTickViewsWithCount:(int)[_ticks count]]; + [self createAndAddBlankTickViewsWithCount:(int)[self.ticks count]]; } -- (bool)areCustomTicksSetupAndNonNull { - return (_customTicksEnabled && _ticks && [_ticks count] > 0); +- (BOOL)areCustomTicksSetupAndNonNull { + return (self.customTicksEnabled && self.ticks && [self.ticks count] > 0); } - (void)createAndAddBlankTickViewsWithCount:(int)count { @@ -245,245 +249,48 @@ - (UIView*)setupCommonTickViewAndAddToSubview { return tick; } -// Calculate the distance differences between each tick according to the pixel width of the slider. -// Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. -- (void)calculateTickDifferences { - positionDiffs = [NSMutableArray new]; // All tick positions (in pixels) relative to the next tick on either side. - fromLeftPositionDiffs = [NSMutableArray new]; // All tick positions (in horizontal pixels) from the far left of the slider view. - -// double thumbSliderWidth = [self thumbImageWidth]; -// double trackWidth = [self thumbImageWidth]; -// double trackXOrigin = [self trackXOrigin]; - - // - [self thumbImageWidth] - //double sliderBasedCenterTrackWidth = [self trackWidth]; // Subtract the slider Diameter, the center of it is the actual start. - - //CGRect trackRect = [slider trackRectForBounds:slider.bounds]; - - double trackWidth = [self trackWidth]; // self.bounds.size.width //TODO: Track Width Bug (see bottom method.) - //double trackWidth2 = self.bounds.size.width; - double sliderThumbDiameter = [self thumbImageWidth]; - - double sliderBasedCenterTrackWidth = trackWidth - (sliderThumbDiameter); // times two because it isn't from origin? - - //TODO: Try this. - //double sliderBasedCenterTrackWidth = self.bounds.size.width - (tickCount * HUMTickWidth); // times two because it isn't from origin? - - //double zeroToOnePercentangeWidthWithoutThumbImage = sliderBasedCenterTrackWidth / self.bounds.size.width; - - //double zeroToOnePercentangeWidthWithoutThumbImage = (sliderBasedCenterTrackWidth / [self trackWidth]) ; - - //double zeroToOnePercentangeWidthWithoutThumbImage = (sliderBasedCenterTrackWidth / trackWidth) ; - - //double fromCenter = zeroToOnePercentangeWidthWithoutThumbImage - 0.5; - - int tickCount = (int)[_ticks count]; //Have Tick views been updated? - - double fromLeftRollingAppender = 0; //TODO: Start at OriginX? - for (NSInteger i = 0; i <= tickCount; i++) { - double currentItem = i == tickCount ? 1 : ((Tick*)self.ticks[i]).position; // zero to one percentage. - double previousItem = i == 0 ? 0 : ((Tick*)self.ticks[i - 1]).position; // zero to one percentage - - double currItemMultValue = currentItem - 0.5; - double prevItemMultValue = previousItem - 0.5; - - double zeroToOnePercentage = currentItem - previousItem; - //double zeroToOnePercentage2 = (currItemMultValue - prevItemMultValue); // * zeroToOnePercentangeWidthWithoutThumbImage; - //double distanceDiff = (zeroToOnePercentage * sliderBasedCenterTrackWidth) - HUMTickWidth; // - HUMTickWidth - double distanceDiff = (zeroToOnePercentage * trackWidth); // - HUMTickWidth - //double distanceDiff = (zeroToOnePercentage2 * [self trackWidth]) - HUMTickWidth; - - -// double distanceDiff2 = ((currItemMultValue * sliderBasedCenterTrackWidth) - (prevItemMultValue * sliderBasedCenterTrackWidth) - HUMTickWidth); -// //double distanceDiff2 = ((currentItem * sliderBasedCenterTrackWidth) - (previousTime * sliderBasedCenterTrackWidth)) - HUMTickWidth; -// if (floor(distanceDiff) != floor(distanceDiff2)) { -// bool shit = true; -// } -// else { -// bool justFine = true; -// //distanceDiff -= HUMTickWidth; -// } - //if (i == 0) { - //distanceDiff += [self trackXOrigin] + (HUMTickWidth / 2.0); //Half of thumb image width. - //distanceDiff += (sliderThumbDiameter / 2) - (HUMTickWidth / 2.0); // - [self trackXOrigin]; //[self trackXOrigin] + - //} - //else if (i == tickCount) { - //distanceDiff += (sliderThumbDiameter / 2) - (HUMTickWidth / 2.0); // - [self trackXOrigin]; - //} - - //Far left and far right tick constraints need to be adjusted in towards the center of the slider by half of the thumb image radius. - if (i == 0 || i == tickCount) { - //distanceDiff += [self thumbImageWidth] / 4;// - HUMTickWidth; - //distanceDiff += HUMTickWidth; - //distanceDiff += [self trackXOrigin]; - } - //distanceDiff = floor(distanceDiff) - HUMTickWidth; //TODO: OriginX? - [positionDiffs insertObject:[NSNumber numberWithDouble: distanceDiff] atIndex:(i)]; - fromLeftRollingAppender += distanceDiff; - [fromLeftPositionDiffs insertObject:[NSNumber numberWithDouble: fromLeftRollingAppender] atIndex:(i)]; - } - NSLog(@"Calculated %d position differentials", (int)[positionDiffs count]); -} - #pragma mark Autolayout - (void)setupTicksAutoLayoutCustomWidths { assert([self areCustomTicksSetupAndNonNull]); - //Store the left, right and bottom constraints for some reason + //Store the position and bottom constraints for some reason NSMutableArray *bottoms = [NSMutableArray array]; - NSMutableArray *lefts = [NSMutableArray array]; - NSMutableArray *rights = [NSMutableArray array]; - - int tickCount = (int)[self.tickViews count]; - - //Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. - [self calculateTickDifferences]; - - //This is the new code to start at the first one. + NSMutableArray *middleConstraints = [NSMutableArray array]; + for (NSInteger i = 0; i < [self.tickViews count]; i++) { - bool isFirst = i == 0 ? true : false; - bool isLast = i == tickCount - 1 ? true : false; UIView *currentItem = self.tickViews[i]; - UIView *previousItem = isFirst ? NULL : self.tickViews[i - 1]; - UIView *nextItem = isLast ? NULL : self.tickViews[i + 1]; - + NSLayoutConstraint *bottomConstraint = [self pinTickBottom:currentItem]; [self addConstraint:bottomConstraint]; [bottoms insertObject:bottomConstraint atIndex:i]; [self pinTickWidthAndHeight:currentItem]; - if (isFirst) { - CGFloat diff = [positionDiffs[i] doubleValue]; - // Pin the first tick to the left of the view. - NSLayoutConstraint *farLeft = [NSLayoutConstraint constraintWithItem:currentItem - attribute:NSLayoutAttributeLeft - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeLeft - multiplier:1 - constant:diff]; - [farLeft setPriority:UILayoutPriorityDefaultHigh]; - [self addConstraint:farLeft]; - [lefts addObject:farLeft]; - } - else { //Left constraints for all but the first element. - CGFloat diff = [positionDiffs[i] doubleValue]; - // Pin the right of the next leftwards tick to the previous leftwards tick - NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:currentItem - attribute:NSLayoutAttributeRight - relatedBy:NSLayoutRelationEqual - toItem:previousItem - attribute:NSLayoutAttributeLeft - multiplier:1 - constant:diff]; - [self addConstraint:left]; - [lefts addObject:left]; - } - - if (isLast) { - CGFloat diff = [positionDiffs[i + 1] doubleValue]; - // Pin the first tick to the left of the view. - NSLayoutConstraint *farRight = [NSLayoutConstraint constraintWithItem:currentItem - attribute:NSLayoutAttributeRight - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeRight - multiplier:1 - constant:diff]; - [farRight setPriority:UILayoutPriorityDefaultHigh]; - [self addConstraint:farRight]; - [rights addObject:farRight]; - } - else { //right constraints for all but the last element - CGFloat diff = [positionDiffs[i + 1] doubleValue]; - // Pin the right of the next leftwards tick to the previous leftwards tick - NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:currentItem - attribute:NSLayoutAttributeLeft - relatedBy:NSLayoutRelationEqual - toItem:nextItem - attribute:NSLayoutAttributeRight - multiplier:1 - constant:diff]; - [self addConstraint:right]; - [rights addObject:right]; - } - } - - NSLog(@"Created %d custom lefts, %d custom rights, and %d custom bottoms", (int)[lefts count], (int)[rights count], (int)[bottoms count]); - - self.allTickBottomConstraints = bottoms; - - self.tickLeftConstraints = lefts; - self.tickRightConstraints = rights; - - [self layoutIfNeeded]; -} + Tick *theTickGuy = _ticks[i]; -- (void)setupTicksAutoLayoutCustomWidths2 { - - assert([self areCustomTicksSetupAndNonNull]); - - //Store the left, right and bottom constraints for some reason - NSMutableArray *bottoms = [NSMutableArray array]; - NSMutableArray *lefts = [NSMutableArray array]; - NSMutableArray *rights = [NSMutableArray array]; - - int tickCount = (int)[self.tickViews count]; - - //Populate the diffs between the ticks for the contraint value. Starting at 0 and ending at 1. Array size will be N+1 where N=number of ticks. There is one extra on the outside. - [self calculateTickDifferences]; - - //This is the new code to start at the first one. - for (NSInteger i = 0; i < [self.tickViews count]; i++) { - bool isFirst = i == 0 ? true : false; - bool isLast = i == tickCount - 1 ? true : false; + // NSLog(@"FrameOriginX: %f, FrameWidth: %f", self.frame.origin.x, self.frame.size.width); + // NSLog(@"BoundsOriginX: %f, BoundsWidth: %f", self.bounds.origin.x, self.bounds.size.width); - UIView *currentItem = self.tickViews[i]; - UIView *previousItem = isFirst ? NULL : self.tickViews[i - 1]; - UIView *nextItem = isLast ? NULL : self.tickViews[i + 1]; - - NSLayoutConstraint *bottomConstraint = [self pinTickBottom:currentItem]; - [self addConstraint:bottomConstraint]; - [bottoms insertObject:bottomConstraint atIndex:i]; - [self pinTickWidthAndHeight:currentItem]; + double constant = [self tickPixelOffsetFromMiddle:theTickGuy]; + + // Pin the middle tick to the middle of the slider. + NSLayoutConstraint *middle = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:constant]; - CGFloat diff = [fromLeftPositionDiffs[i] doubleValue]; - // Pin the first tick to the left of the view. - NSLayoutConstraint *farLeft = [NSLayoutConstraint constraintWithItem:currentItem - attribute:NSLayoutAttributeLeft - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeLeft - multiplier:1 - constant:diff]; - [farLeft setPriority:UILayoutPriorityDefaultHigh]; - [self addConstraint:farLeft]; - [lefts addObject:farLeft]; - - diff = [self trackWidth] - diff; - // Pin the first tick to the left of the view. - NSLayoutConstraint *farRight = [NSLayoutConstraint constraintWithItem:currentItem - attribute:NSLayoutAttributeRight - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeRight - multiplier:1 - constant:diff]; - [farRight setPriority:UILayoutPriorityDefaultHigh]; - [self addConstraint:farRight]; - [rights addObject:farRight]; + [self addConstraint:middle]; + [middleConstraints addObject:middle]; } - - NSLog(@"Created %d custom lefts, %d custom rights, and %d custom bottoms", (int)[lefts count], (int)[rights count], (int)[bottoms count]); - + self.allTickBottomConstraints = bottoms; - - self.tickLeftConstraints = lefts; - self.tickRightConstraints = rights; - + self.middleTickConstraints = middleConstraints; + [self layoutIfNeeded]; } @@ -757,9 +564,11 @@ - (void)pinView1Center:(UIView *)view1 toView2Center:(UIView *)view2 - (void)layoutSubviews { + trackRect = [self trackRectForBounds:self.bounds]; + [super layoutSubviews]; if ([self areCustomTicksSetupAndNonNull]) { - [self updateCustomTickConstraintsIfNeeded2]; + [self updateCustomTickConstraintsIfNeeded]; } else { [self updateLeftTickConstraintsIfNeeded]; @@ -791,62 +600,24 @@ - (void)updateCustomTickConstraintsIfNeeded assert([self areCustomTicksSetupAndNonNull]); int tickCount = (int)[self.tickViews count]; - - // Calculate position differences if necessary. - // TODO Cleanup - if (!positionDiffs || [positionDiffs count] != tickCount + 1) { - [self calculateTickDifferences]; - } - - NSLayoutConstraint *firstLeft = self.tickLeftConstraints.firstObject; // special case - pin left of view to left-most tick. - NSLayoutConstraint *lastRight = self.tickRightConstraints.lastObject; // special case - pin right of view to right-most tick. - - //if (firstLeft.constant != ((NSNumber*)positionDiffs.firstObject).doubleValue) { - firstLeft.constant = ((NSNumber*)positionDiffs.firstObject).doubleValue; - lastRight.constant = ((NSNumber*)positionDiffs.lastObject).doubleValue; - - //This is the new code to start at the first one. - for (NSInteger i = 1; i < tickCount; i++) { - NSLayoutConstraint *leftConstraint = _tickLeftConstraints[i]; - NSLayoutConstraint *rightConstraint = _tickRightConstraints[i]; - leftConstraint.constant = ((NSNumber*)positionDiffs[i]).doubleValue; - rightConstraint.constant = ((NSNumber*)positionDiffs[i+1]).doubleValue; // we have one more position diff than ticks. - } - - [self layoutIfNeeded]; - //} -} - -- (void)updateCustomTickConstraintsIfNeeded2 -{ - assert([self areCustomTicksSetupAndNonNull]); - int tickCount = (int)[self.tickViews count]; + NSLayoutConstraint *firstLeft = self.middleTickConstraints.firstObject; - // Calculate position differences if necessary. - // TODO Cleanup - if (!positionDiffs || [positionDiffs count] != tickCount + 1) { - [self calculateTickDifferences]; - } + Tick *firstTick = self.ticks[0]; - NSLayoutConstraint *firstLeft = self.tickLeftConstraints.firstObject; // special case - pin left of view to left-most tick. - NSLayoutConstraint *lastRight = self.tickRightConstraints.lastObject; // special case - pin right of view to right-most tick. + CGFloat constant = [self tickPixelOffsetFromMiddle:firstTick]; - //if (firstLeft.constant != ((NSNumber*)positionDiffs.firstObject).doubleValue) { - firstLeft.constant = ((NSNumber*)positionDiffs.firstObject).doubleValue; - lastRight.constant = ((NSNumber*)positionDiffs.lastObject).doubleValue; + if (firstLeft.constant != constant) { + + //This is the new code to start at the first one. + for (NSInteger i = 0; i < tickCount; i++) { + NSLayoutConstraint *middleConstraint = self.middleTickConstraints[i]; + Tick *theTick = self.ticks[i]; + middleConstraint.constant = [self tickPixelOffsetFromMiddle:theTick]; + } - //This is the new code to start at the first one. - for (NSInteger i = 1; i < tickCount; i++) { - NSLayoutConstraint *leftConstraint = _tickLeftConstraints[i]; - NSLayoutConstraint *rightConstraint = _tickRightConstraints[i]; - double fromLeft = ((NSNumber*)fromLeftPositionDiffs[i]).doubleValue; - leftConstraint.constant = fromLeft; - rightConstraint.constant = [self trackWidth] - fromLeft; // we have one more position diff than ticks. + [self layoutIfNeeded]; } - - [self layoutIfNeeded]; - //} } #pragma mark - Overridden Setters @@ -970,9 +741,6 @@ - (UIColor *)desaturatedColorForSide:(HUMSliderSide)side - (UIImageView *)imageViewForSide:(HUMSliderSide)side saturated:(BOOL)saturated { - //TODO: Figure out what this is used for and update it. -#pragma mark - warning, see the thing above. - switch (side) { case HUMSliderSideLeft: if (saturated) { @@ -1007,52 +775,75 @@ - (void)setTickColor:(UIColor *)tickColor - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { if ([self areCustomTicksSetupAndNonNull]) { - [self updateCustomTickConstraintsIfNeeded]; [self animateAllTicksInCustomWidths:YES]; - [self popTickIfNeededFromTouch:touch]; } else { - // Update the width [self updateLeftTickConstraintsIfNeeded]; [self animateAllTicksIn:YES]; - [self popTickIfNeededFromTouch:touch]; } + [self popTickIfNeededFromTouch:touch]; + return [super beginTrackingWithTouch:touch withEvent:event]; } -// TODO: Hook this up +- (void)updateTickHeights { + #warning - fix this method. + //TODO: Reuse this fromn the pop method. + + CGRect trackRect = [self trackRectForBounds:self.bounds]; + CGRect thumbRect = [self thumbRectForBounds:self.bounds + trackRect:trackRect + value:self.value]; + + #warning - there may be an issue calculating the slider location. + CGFloat sliderLoc = CGRectGetMidX(thumbRect); + + // Animate tick based on the thumb location + for (NSInteger i = 0; i < self.tickViews.count; i++) { + if ([self areCustomTicksSetupAndNonNull]) { + [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; + } + else { + [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; + } + } + +} + - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { +#warning - fix this method. + assert ([self areCustomTicksSetupAndNonNull]); - UIView *tick = self.tickViews[tickIndex]; + //UIView *tick = self.tickViews[tickIndex]; - NSLog(@" Track X Origin: %f", self.trackXOrigin); + //NSLog(@" Track X Origin: %f", self.trackXOrigin); - double distanceFromLeft = ((NSNumber*)fromLeftPositionDiffs[tickIndex]).doubleValue; + //double distanceFromLeft = ((NSNumber*)fromLeftPositionDiffs[tickIndex]).doubleValue; - double thumbSliderRadius = [self thumbImageWidth] / 2; + //double thumbSliderRadius = [self thumbImageWidth] / 2; - CGFloat startSegmentX = distanceFromLeft - thumbSliderRadius; //TODO: Make a constant for the interval - from AdjustedThumbSlider subclass. - CGFloat endSegmentX = distanceFromLeft + thumbSliderRadius; + //CGFloat startSegmentX = distanceFromLeft - thumbSliderRadius; //TODO: Make a constant for the interval - from AdjustedThumbSlider subclass. + //CGFloat endSegmentX = distanceFromLeft + thumbSliderRadius; - CGFloat desiredOrigin; - if (startSegmentX <= touchX && endSegmentX > touchX) { - // Pop up. - desiredOrigin = [self tickPoppedPosition]; - } else { - // Bring down. - desiredOrigin = [self tickInNotPoppedPositon]; - } - - if (CGRectGetMinY(tick.frame) != desiredOrigin) { - [self animateTickAtIndex:tickIndex - toYOrigin:desiredOrigin - withDuration:self.tickMovementAnimationDuration - delay:0]; - } // else tick is already where it needs to be. +// CGFloat desiredOrigin; +// if (startSegmentX <= touchX && endSegmentX > touchX) { +// // Pop up. +// desiredOrigin = [self tickPoppedPosition]; +// } else { +// // Bring down. +// desiredOrigin = [self tickInNotPoppedPositon]; +// } +// +// if (CGRectGetMinY(tick.frame) != desiredOrigin) { +// [self animateTickAtIndex:tickIndex +// toYOrigin:desiredOrigin +// withDuration:self.tickMovementAnimationDuration +// delay:0]; + //} // else tick is already where it needs to be. } - (void)animateTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX @@ -1089,21 +880,17 @@ - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event - (void)popTickIfNeededFromTouch:(UITouch *)touch { -#pragma mark - Warning - update this method for custom tick widths. - //TODO: This method needs to be updated for the custom tick widths. - - // Figure out where the hell the thumb is. CGRect trackRect = [self trackRectForBounds:self.bounds]; CGRect thumbRect = [self thumbRectForBounds:self.bounds trackRect:trackRect value:self.value]; -#warning - there may be an issue calculating the slider location. CGFloat sliderLoc = CGRectGetMidX(thumbRect); // Animate tick based on the thumb location for (NSInteger i = 0; i < self.tickViews.count; i++) { if ([self areCustomTicksSetupAndNonNull]) { + #warning - this isn't working currently, fix it up [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; } else { @@ -1271,19 +1058,12 @@ - (CGFloat)trackYOrigin return CGRectGetMinY(trackRect); } -#warning - replace this with something more dynamic. - (CGFloat)segmentWidth { CGRect trackRect = [self trackRectForBounds:self.bounds]; return floorf(CGRectGetWidth(trackRect) / self.sectionCount); } -- (CGFloat)trackWidth { - CGRect trackRect = [self trackRectForBounds:self.bounds]; - return CGRectGetWidth(trackRect); - //return floorf(CGRectGetWidth(trackRect)); -} - - (NSInteger)middleTickIndex { return floor(self.tickViews.count / 2); @@ -1320,6 +1100,12 @@ - (CGFloat)tickPoppedPosition return [self tickInNotPoppedPositon] - [self tickInToPoppedDifferential] + self.pointAdjustmentForCustomThumb; } +- (CGFloat)tickPixelOffsetFromMiddle:(Tick*)tick { + double trackWidth = trackRect.size.width - [self thumbImageWidth] + trackRect.origin.x; // :) + double constant = (tick.position * trackWidth) - (trackWidth / 2); + return constant; +} + - (double)thumbImageWidth // default thumb image is 30 px, { // Won't fail to compute the thumb image width unless its width is 0; From da80763788f025b81ec1c72e6959092505a41a37 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 20:24:49 -0700 Subject: [PATCH 06/33] Final cleanup --- Library/HUMSlider.h | 12 +++- Library/HUMSlider.m | 137 +++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 74 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index 7157b52..71a81da 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -66,7 +66,10 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { @property (nonatomic) NSTimeInterval nextTickAnimationDelay; ///Turns the custom tick feature on and off. -@property (nonatomic) bool customTicksEnabled; +@property (nonatomic) BOOL customTicksEnabled; + +///Ticks animate down to track line when user is not actively moving the slider. +@property (nonatomic) BOOL lowerTicksOnInactiveTouch; #pragma mark - Setters/Getters for individual sides @@ -116,7 +119,12 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { */ - (UIColor *)desaturatedColorForSide:(HUMSliderSide)side; -// TODO: Update the tick heights. +/** + * Method to manually update the tick heights to the thumb image as + * if the touch was tracking. This comes in handy if the slider will + * move separate from user input, like for song playback or other non- + * user driven input. + */ - (void)updateTickHeights; @end diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 7a46146..e4e1995 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -15,13 +15,16 @@ static NSTimeInterval const HUMTickAnimationDelay = 0.025; // Positions -static CGFloat const HUMTickOutToInDifferential = 8; +static CGFloat const HUMTickOutToInDifferential = 9; static CGFloat const HUMImagePadding = 8; // Sizes static CGFloat const HUMTickHeight = 8; static CGFloat const HUMTickWidth = 1; +// Default Constants +static CGFloat const DefaultThumbPxWidth = 30; //Size of apple's default thumb icon. + @implementation Tick // Constructor for a tick - (id)initWithPosition:(double)position { @@ -40,8 +43,8 @@ @interface HUMSlider () @property (nonatomic) NSArray *allTickBottomConstraints; //Constraint storage for evenly spaced tick constraints. -@property (nonatomic) NSArray *leftTickRightConstraints; //Confusing name.. what is a left tick? Left of middle? -@property (nonatomic) NSArray *rightTickLeftConstraints; //Confusing name.. what is a right tick? Right of middle? +@property (nonatomic) NSArray *leftTickRightConstraints; //FUTURE, use the middleTickConstraints strategy for equal spaced ticks +@property (nonatomic) NSArray *rightTickLeftConstraints; //Constraint storage for dynamically spaced tick constraints. @property (nonatomic) NSArray *middleTickConstraints; @@ -61,10 +64,6 @@ @interface HUMSlider () @end @implementation HUMSlider { -#warning - clean this up -// NSMutableArray *positionDiffs; //For custom tick views - diff between each tick in slider px. -// NSMutableArray *fromLeftPositionDiffs; //Distance from left in px for each custom tick. -// CGFloat thumbImageWidth; // Reference to last computed thumb width. CGRect trackRect; // store the track width from the layoutSubviews. } @@ -76,6 +75,7 @@ - (void)commonInit trackRect = CGRectZero; [self thumbImageWidth]; // Lazy init of initial calc of thumb image width. + self.lowerTicksOnInactiveTouch = true; //default to lowering them. self.customTicksEnabled = true; //default to true self.enableTicksTransparencyOnIdle = false; // keep ticks at all times. @@ -130,10 +130,7 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder #pragma mark - Ticks -#warning - Create method to add all ticks. - - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { -#warning - When doing the constraint from center x, the ticks do not need to be in order anymore if ([self.ticks count] == 0) { [self.ticks addObject:tick]; @@ -151,6 +148,7 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { if (refreshView) { [self setupTickViews]; + [self updateTickHeights]; } } @@ -573,7 +571,6 @@ - (void)layoutSubviews else { [self updateLeftTickConstraintsIfNeeded]; } - } // First method that is called when animating ticks in. @@ -789,61 +786,61 @@ - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event } - (void)updateTickHeights { - #warning - fix this method. - //TODO: Reuse this fromn the pop method. - - CGRect trackRect = [self trackRectForBounds:self.bounds]; - CGRect thumbRect = [self thumbRectForBounds:self.bounds - trackRect:trackRect - value:self.value]; - - #warning - there may be an issue calculating the slider location. - CGFloat sliderLoc = CGRectGetMidX(thumbRect); - - // Animate tick based on the thumb location - for (NSInteger i = 0; i < self.tickViews.count; i++) { - if ([self areCustomTicksSetupAndNonNull]) { - [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; - } - else { - [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; - } - } + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateTickHeights]; + return; + }); + } + + CGRect trackRect = [self trackRectForBounds:self.bounds]; + CGRect thumbRect = [self thumbRectForBounds:self.bounds + trackRect:trackRect + value:self.value]; + + CGFloat sliderLoc = CGRectGetMidX(thumbRect); + + // Animate tick based on the thumb location + for (NSInteger i = 0; i < self.tickViews.count; i++) { + if ([self areCustomTicksSetupAndNonNull]) { + [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; + } + else { + [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; + } + } } - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { -#warning - fix this method. - assert ([self areCustomTicksSetupAndNonNull]); - //UIView *tick = self.tickViews[tickIndex]; - - //NSLog(@" Track X Origin: %f", self.trackXOrigin); - - //double distanceFromLeft = ((NSNumber*)fromLeftPositionDiffs[tickIndex]).doubleValue; + UIView *tick = self.tickViews[tickIndex]; + + NSLayoutConstraint *constraint = self.middleTickConstraints[tickIndex]; - //double thumbSliderRadius = [self thumbImageWidth] / 2; + CGFloat distanceFromLeft = (trackRect.size.width / 2) + (constraint.constant); + CGFloat thumbSliderRadius = [self thumbImageWidth] / 2; - //CGFloat startSegmentX = distanceFromLeft - thumbSliderRadius; //TODO: Make a constant for the interval - from AdjustedThumbSlider subclass. - //CGFloat endSegmentX = distanceFromLeft + thumbSliderRadius; + CGFloat startSegmentX = distanceFromLeft - thumbSliderRadius; //TODO: Make a constant for the interval - from AdjustedThumbSlider subclass. + CGFloat endSegmentX = distanceFromLeft + thumbSliderRadius; -// CGFloat desiredOrigin; -// if (startSegmentX <= touchX && endSegmentX > touchX) { -// // Pop up. -// desiredOrigin = [self tickPoppedPosition]; -// } else { -// // Bring down. -// desiredOrigin = [self tickInNotPoppedPositon]; -// } -// -// if (CGRectGetMinY(tick.frame) != desiredOrigin) { -// [self animateTickAtIndex:tickIndex -// toYOrigin:desiredOrigin -// withDuration:self.tickMovementAnimationDuration -// delay:0]; - //} // else tick is already where it needs to be. + CGFloat desiredOrigin; + if (startSegmentX <= touchX && endSegmentX > touchX) { + // Pop up. + desiredOrigin = [self tickPoppedPosition]; + } else{ + // Bring down. + desiredOrigin = [self tickInNotPoppedPositon]; + } + + if (CGRectGetMinY(tick.frame) != desiredOrigin) { + [self animateTickAtIndex:tickIndex + toYOrigin:desiredOrigin + withDuration:self.tickMovementAnimationDuration + delay:0]; + } // else tick is already where it needs to be. } - (void)animateTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX @@ -890,7 +887,6 @@ - (void)popTickIfNeededFromTouch:(UITouch *)touch // Animate tick based on the thumb location for (NSInteger i = 0; i < self.tickViews.count; i++) { if ([self areCustomTicksSetupAndNonNull]) { - #warning - this isn't working currently, fix it up [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; } else { @@ -917,14 +913,17 @@ - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - [self returnPosition]; //TODO: WTF does return position do? This just calls the animage method again... + [self returnPosition]; [super touchesEnded:touches withEvent:event]; } - (void)returnPosition { - //TODO: This is our guy! + if (self.lowerTicksOnInactiveTouch == NO) { + return; + } + if ([self areCustomTicksSetupAndNonNull]) { [self animateAllTicksInCustomWidths:NO]; } @@ -1027,8 +1026,6 @@ - (void)animateTickAtIndex:(NSInteger)index withDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay { - - NSLayoutConstraint *constraint = self.allTickBottomConstraints[index]; constraint.constant = yOrigin; @@ -1106,18 +1103,14 @@ - (CGFloat)tickPixelOffsetFromMiddle:(Tick*)tick { return constant; } -- (double)thumbImageWidth // default thumb image is 30 px, +- (CGFloat)thumbImageWidth // default thumb image is 30 px, { - // Won't fail to compute the thumb image width unless its width is 0; - if (!thumbImageWidth || thumbImageWidth == 0) { - - double thumbImageWidthFromSetImage = self.currentThumbImage.size.width; - if (!thumbImageWidthFromSetImage || thumbImageWidthFromSetImage == 0) { - thumbImageWidth = 30; //Guess and check default value for thumb image on UISlider. - } - else { - thumbImageWidth = thumbImageWidthFromSetImage; - } + double imgThumbImageWidth = self.currentThumbImage.size.width; + if (imgThumbImageWidth && imgThumbImageWidth != 0 && imgThumbImageWidth != thumbImageWidth) { + thumbImageWidth = imgThumbImageWidth; + } + else if (!thumbImageWidth || thumbImageWidth == 0) { // No custom image set, use 30 + thumbImageWidth = DefaultThumbPxWidth; } return thumbImageWidth; } From c77a69dbfad0d01b9c57192a6029043ec85f937d Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 20:45:20 -0700 Subject: [PATCH 07/33] Updating the readme --- Library/HUMSlider.m | 1 - README.md | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index e4e1995..239d748 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -809,7 +809,6 @@ - (void)updateTickHeights { [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; } } - } - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX diff --git a/README.md b/README.md index e9178a7..19efa03 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,45 @@ A quick programmatic example of the most common use case: // What color should the image be when the thumb is not close to it? slider.desaturatedColor = [[UIColor redColor] colorWithAlpha:0.5f]; - // How many ticks do you want? + // How many ticks do you want? (Only works if customTicksEnabled == false) slider.sectionCount = 11; // This should be an odd number. // What color should the ticks be? slider.tickColor = [UIColor blackColor]; + + //Turns the custom tick feature on and off, defaults to NO + slider.customTicksEnabled = YES; + + //Ticks animate down to track line when user is not actively moving the slider. Defaults to YES + slider.lowerTicksOnInactiveTouch = NO; + + //Ticks will fade out when the user is not actively moving the touch slider. Defaults to YES + slider.enableTicksTransparencyOnIdle = NO; ``` +###Custom Ticks + +```objectivec + + //Init custom ticks with one tick, at 1/3 position up the slider + Tick *oneThird = [[Tick alloc] initWithPosition: 0.333]; + [slider addTick:oneThird willRefreshView:false]; + slider.customTicksEnabled = true; + + //Tick Removal + [slider removeTickAtIndex:0]; +``` + +###Custom Tracking + +- Simply call the updateTickHeights method regularly if you are programmatically + moving the slider, and want the ticks the same as if the user is moving them. + +```objectivec + [slider updateTickHeights] +``` + + Full code is available in the sample app included in this repo. ##Usage notes @@ -55,4 +87,5 @@ Full code is available in the sample app included in this repo. #Contributors - Design: [Aaron Shekey](http://github.com/aaronshekey) -- Engineering: [Ellen Shapiro](http://github.com/designatednerd) \ No newline at end of file +- Engineering: [Ellen Shapiro](http://github.com/designatednerd) +- Custom Ticks Feature: [Jeffrey Blayney](https://github.com/thejeff77) \ No newline at end of file From 8aa87a5752dcb71a8acdd30b7aaf3571e4419c88 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 20:48:13 -0700 Subject: [PATCH 08/33] fixing heading formatting --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 19efa03..ba853ad 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A slider control with auto-appearing ticks and saturating images at each end. St ![](slider_in_action.gif) -##Setup +## Setup To use this control, we strongly recommend using [CocoaPods](http://cocoapods.org). To do so add the following to your `Podfile`: @@ -15,7 +15,7 @@ pod 'HUMSlider', ~>'1.0' and then `pod install`. -##Usage +## Usage A quick programmatic example of the most common use case: @@ -48,7 +48,7 @@ A quick programmatic example of the most common use case: slider.enableTicksTransparencyOnIdle = NO; ``` -###Custom Ticks +## Custom Ticks ```objectivec @@ -61,7 +61,7 @@ A quick programmatic example of the most common use case: [slider removeTickAtIndex:0]; ``` -###Custom Tracking +## Custom Tracking - Simply call the updateTickHeights method regularly if you are programmatically moving the slider, and want the ticks the same as if the user is moving them. @@ -73,7 +73,7 @@ A quick programmatic example of the most common use case: Full code is available in the sample app included in this repo. -##Usage notes +## Usage notes - The number of ticks **must be odd** - otherwise pretty much all the math for centering things breaks spectacularly. Attempting to add an even number of ticks will cause an assertion failure during development. - If you are using a custom thumb image which has some clear space at the top, use the `pointAdjustmentForCustomThumb` property to compensate for this. @@ -84,7 +84,7 @@ Full code is available in the sample app included in this repo. - If you set the `saturatedColor` or `desaturatedColor` properties, it will set the same color on both sides. Use the `setSaturatedColor:forSide:` and `setDesaturatedColor:forSide` to set separate colors per side. -#Contributors +## Contributors - Design: [Aaron Shekey](http://github.com/aaronshekey) - Engineering: [Ellen Shapiro](http://github.com/designatednerd) From a162d61d5e88251e923952cb9d4b060d5a5c5f69 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 20:49:55 -0700 Subject: [PATCH 09/33] Added comment to clarify refreshView param --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba853ad..74d1c55 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ A quick programmatic example of the most common use case: ```objectivec - //Init custom ticks with one tick, at 1/3 position up the slider + //Init custom ticks with one tick, at 1/3 position up the slider. If adding many, refresh view on final addition. Tick *oneThird = [[Tick alloc] initWithPosition: 0.333]; - [slider addTick:oneThird willRefreshView:false]; + [slider addTick:oneThird willRefreshView:true]; slider.customTicksEnabled = true; //Tick Removal From 750d43d182a6dbf78b54a2f6b8de1aad21c1c5d3 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 21:03:45 -0700 Subject: [PATCH 10/33] Resolving minor code comments --- Library/HUMSlider.h | 4 ++-- Library/HUMSlider.m | 20 +++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index 71a81da..35cf351 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -78,7 +78,7 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { * Inserts a tick at a position. * @param tick. The tick with the set position between 0 and 1 */ -- (void)addTick:(Tick*)tick willRefreshView:(bool)refreshView; +- (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView; /** * Refreshes the view in a custom way, in case you didn't do it for each tick addition. @@ -89,7 +89,7 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { * Removes the tick at the given index. . * @param index. The tick Index with the set position between 0 and 1 */ -- (void)removeTickAtIndex:(uint)index; +- (void)removeTickAtIndex:(NSUInteger)index; /** * Sets the color to use as the fully-saturated color on selected side. diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 239d748..e8e476b 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -27,7 +27,7 @@ @implementation Tick // Constructor for a tick -- (id)initWithPosition:(double)position { +- (id)initWithPosition:(CGFloat)position { NSAssert(position >= 0 && position <= 1, @"Position must be between 0 and 1"); self = [super init]; if (self) { @@ -136,9 +136,9 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { [self.ticks addObject:tick]; } else { // Sorted-ly add the tick in the right sorted order. - unsigned long index = [self.ticks count]; - for (Tick *tick_itr in [self.ticks reverseObjectEnumerator]) { - if (tick.position >= tick_itr.position) { + NSUInteger index = [self.ticks count]; + for (Tick *tickItr in [self.ticks reverseObjectEnumerator]) { + if (tick.position >= tickItr.position) { [self.ticks insertObject:tick atIndex:index]; break; } @@ -152,7 +152,7 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { } } -- (void)removeTickAtIndex:(uint)index { +- (void)removeTickAtIndex:(NSUInteger)index { [_ticks removeObjectAtIndex:index]; } @@ -216,18 +216,18 @@ - (void)clearLayoutConstraintList:(NSArray*)list { } - (void)setupSpacedTickViews { - [self createAndAddBlankTickViewsWithCount:(int)self.sectionCount]; + [self createAndAddBlankTickViewsWithCount:(NSUInteger)self.sectionCount]; } - (void)setupCustomTickViews { - [self createAndAddBlankTickViewsWithCount:(int)[self.ticks count]]; + [self createAndAddBlankTickViewsWithCount:(NSUInteger)[self.ticks count]]; } - (BOOL)areCustomTicksSetupAndNonNull { return (self.customTicksEnabled && self.ticks && [self.ticks count] > 0); } -- (void)createAndAddBlankTickViewsWithCount:(int)count { +- (void)createAndAddBlankTickViewsWithCount:(NSUInteger)count { NSMutableArray *tickBuilder = [NSMutableArray array]; for (NSInteger i = 0; i < count; i++) { UIView *tick = [self setupCommonTickViewAndAddToSubview]; @@ -445,8 +445,6 @@ - (void)sliderAdjusted { CGFloat halfValue = (self.minimumValue + self.maximumValue) / 2.0f; - //TODO: Do we need to do anything special here? What does this do? - if (self.value > halfValue) { self.rightSaturatedImageView.alpha = (self.value - halfValue) / halfValue; self.leftSaturatedImageView.alpha = 0; @@ -596,7 +594,7 @@ - (void)updateCustomTickConstraintsIfNeeded { assert([self areCustomTicksSetupAndNonNull]); - int tickCount = (int)[self.tickViews count]; + NSUInteger tickCount = [self.tickViews count]; NSLayoutConstraint *firstLeft = self.middleTickConstraints.firstObject; From 244fbb6387b3e2ea6bd1862df014e4fc699193e0 Mon Sep 17 00:00:00 2001 From: thejeff77 Date: Thu, 22 Feb 2018 21:08:25 -0700 Subject: [PATCH 11/33] Update project.pbxproj Removing team info from PR --- HUMSliderSample.xcodeproj/project.pbxproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/HUMSliderSample.xcodeproj/project.pbxproj b/HUMSliderSample.xcodeproj/project.pbxproj index 9e42070..06d2495 100644 --- a/HUMSliderSample.xcodeproj/project.pbxproj +++ b/HUMSliderSample.xcodeproj/project.pbxproj @@ -182,7 +182,6 @@ TargetAttributes = { 9BA867DA1A4DF3B900121ED5 = { CreatedOnToolsVersion = 6.1.1; - DevelopmentTeam = ZAR5QX7MAH; }; 9BA867F31A4DF3B900121ED5 = { CreatedOnToolsVersion = 6.1.1; @@ -376,7 +375,6 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = ZAR5QX7MAH; INFOPLIST_FILE = HUMSliderSample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -388,7 +386,6 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = ZAR5QX7MAH; INFOPLIST_FILE = HUMSliderSample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; From 619bd5c52190be30c3d7678f6be6721fddf3d8c3 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 21:09:21 -0700 Subject: [PATCH 12/33] Changing to NSUInteger --- Library/HUMSlider.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index 35cf351..4aa429b 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -14,8 +14,8 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { }; @interface Tick : NSObject -- (id)initWithPosition:(double)position; -@property double position; //Number between 0 and 1 indicating the slider position of the tick. +- (id)initWithPosition:(NSUInteger)position; +@property NSUInteger position; //Number between 0 and 1 indicating the slider position of the tick. @end /** From 6607181ffca65e5cd1336ceeee1fdf5f662c557f Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 21:11:50 -0700 Subject: [PATCH 13/33] Updating defaults to documented values. --- Library/HUMSlider.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index e8e476b..0017b50 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -76,8 +76,8 @@ - (void)commonInit [self thumbImageWidth]; // Lazy init of initial calc of thumb image width. self.lowerTicksOnInactiveTouch = true; //default to lowering them. - self.customTicksEnabled = true; //default to true - self.enableTicksTransparencyOnIdle = false; // keep ticks at all times. + self.customTicksEnabled = false; //default to true + self.enableTicksTransparencyOnIdle = true; // keep ticks at all times. // Set default values. self.sectionCount = 9; From 89f9b917ea1655076cc49621a28a58d6014ececb Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 22 Feb 2018 21:30:18 -0700 Subject: [PATCH 14/33] oops --- Library/HUMSlider.h | 4 ++-- Library/HUMSlider.m | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index 4aa429b..e7d3dee 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -14,8 +14,8 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { }; @interface Tick : NSObject -- (id)initWithPosition:(NSUInteger)position; -@property NSUInteger position; //Number between 0 and 1 indicating the slider position of the tick. +- (id)initWithPosition:(CGFloat)position; +@property CGFloat position; //Number between 0 and 1 indicating the slider position of the tick. @end /** diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 0017b50..8f87d3c 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -268,9 +268,6 @@ - (void)setupTicksAutoLayoutCustomWidths { Tick *theTickGuy = _ticks[i]; - // NSLog(@"FrameOriginX: %f, FrameWidth: %f", self.frame.origin.x, self.frame.size.width); - // NSLog(@"BoundsOriginX: %f, BoundsWidth: %f", self.bounds.origin.x, self.bounds.size.width); - double constant = [self tickPixelOffsetFromMiddle:theTickGuy]; // Pin the middle tick to the middle of the slider. From ce407bfa7a4b02c2cca60ebf642ed87863acaba3 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Mon, 5 Mar 2018 13:07:17 -0700 Subject: [PATCH 15/33] reverting default size changes --- Library/HUMSlider.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 8f87d3c..92d3e0b 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -15,11 +15,11 @@ static NSTimeInterval const HUMTickAnimationDelay = 0.025; // Positions -static CGFloat const HUMTickOutToInDifferential = 9; +static CGFloat const HUMTickOutToInDifferential = 8; static CGFloat const HUMImagePadding = 8; // Sizes -static CGFloat const HUMTickHeight = 8; +static CGFloat const HUMTickHeight = 6; static CGFloat const HUMTickWidth = 1; // Default Constants From 0212379092f4b70c1348cd6fbb6a99cd8082b684 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Mon, 5 Mar 2018 13:16:04 -0700 Subject: [PATCH 16/33] added logic to squeeze the ticks to the slider --- Library/HUMSlider.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 92d3e0b..2e1ea71 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -15,7 +15,7 @@ static NSTimeInterval const HUMTickAnimationDelay = 0.025; // Positions -static CGFloat const HUMTickOutToInDifferential = 8; +static CGFloat const HUMTickOutToInDifferential = 10; static CGFloat const HUMImagePadding = 8; // Sizes @@ -824,6 +824,8 @@ - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat if (startSegmentX <= touchX && endSegmentX > touchX) { // Pop up. desiredOrigin = [self tickPoppedPosition]; + CGFloat Xdiff = fmin(fabs(touchX - startSegmentX), fabs(touchX - endSegmentX)); + desiredOrigin -= (Xdiff * 0.5); } else{ // Bring down. desiredOrigin = [self tickInNotPoppedPositon]; From 6b3b8ef1b4ecb2222d6d3c267fc8ca7a2dcf4877 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Mon, 5 Mar 2018 14:01:00 -0700 Subject: [PATCH 17/33] Made the ticks animate and squeeze to the slider. Fixed a bug where the custom thumb adjustment value being positive should pop the tick up higher instead of the inverse, because the differentials are more negative the higher they pop up. --- Library/HUMSlider.m | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 2e1ea71..fd63e4b 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -15,7 +15,7 @@ static NSTimeInterval const HUMTickAnimationDelay = 0.025; // Positions -static CGFloat const HUMTickOutToInDifferential = 10; +static CGFloat const HUMTickOutToInDifferential = 8; static CGFloat const HUMImagePadding = 8; // Sizes @@ -806,6 +806,8 @@ - (void)updateTickHeights { } } +#warning - thumbHeight method may do the same thing as self thumbImageWidth. + - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { assert ([self areCustomTicksSetupAndNonNull]); @@ -814,18 +816,22 @@ - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat NSLayoutConstraint *constraint = self.middleTickConstraints[tickIndex]; - CGFloat distanceFromLeft = (trackRect.size.width / 2) + (constraint.constant); + CGFloat tickDistanceFromLeft = (trackRect.size.width / 2) + (constraint.constant) + trackRect.origin.x; CGFloat thumbSliderRadius = [self thumbImageWidth] / 2; - CGFloat startSegmentX = distanceFromLeft - thumbSliderRadius; //TODO: Make a constant for the interval - from AdjustedThumbSlider subclass. - CGFloat endSegmentX = distanceFromLeft + thumbSliderRadius; + CGFloat startSegmentX = tickDistanceFromLeft - thumbSliderRadius; //TODO: Make a constant for the interval - from AdjustedThumbSlider subclass. + CGFloat endSegmentX = tickDistanceFromLeft + thumbSliderRadius; CGFloat desiredOrigin; if (startSegmentX <= touchX && endSegmentX > touchX) { // Pop up. desiredOrigin = [self tickPoppedPosition]; - CGFloat Xdiff = fmin(fabs(touchX - startSegmentX), fabs(touchX - endSegmentX)); - desiredOrigin -= (Xdiff * 0.5); + CGFloat Xdiff = fabs(touchX - tickDistanceFromLeft);//fmin(fabs(touchX - startSegmentX), fabs(touchX - endSegmentX)); + CGFloat zeroBased = Xdiff / ([self thumbImageWidth] / 2); + CGFloat diffZeroBased = tan(acos(zeroBased)) * zeroBased; + CGFloat diff = (1 - diffZeroBased) * ([self thumbImageWidth] / 2); + CGFloat notPopped = [self tickInNotPoppedPositon]; + desiredOrigin += diff; // Add because the desired origin is negative the higher it pops. } else{ // Bring down. desiredOrigin = [self tickInNotPoppedPositon]; @@ -1090,7 +1096,7 @@ - (CGFloat)tickInNotPoppedPositon - (CGFloat)tickPoppedPosition { - return [self tickInNotPoppedPositon] - [self tickInToPoppedDifferential] + self.pointAdjustmentForCustomThumb; + return [self tickInNotPoppedPositon] - [self tickInToPoppedDifferential] - self.pointAdjustmentForCustomThumb; } - (CGFloat)tickPixelOffsetFromMiddle:(Tick*)tick { From 2e71a848bb057a53fe3a075cdee4fcb2766f44c2 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Sun, 11 Mar 2018 18:33:28 -0600 Subject: [PATCH 18/33] Added a remove all method --- Library/HUMSlider.h | 7 ++++++- Library/HUMSlider.m | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index e7d3dee..ce3148b 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -89,7 +89,12 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { * Removes the tick at the given index. . * @param index. The tick Index with the set position between 0 and 1 */ -- (void)removeTickAtIndex:(NSUInteger)index; +- (void)removeTickAtIndex:(NSUInteger)index refreshView:(BOOL)refreshView; + +/** + * Remove all of the ticks + */ +- (void)removeAllTicks; /** * Sets the color to use as the fully-saturated color on selected side. diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index fd63e4b..4287601 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -152,8 +152,21 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { } } -- (void)removeTickAtIndex:(NSUInteger)index { +- (void)removeTickAtIndex:(NSUInteger)index refreshView:(BOOL)refreshView { [_ticks removeObjectAtIndex:index]; + if (refreshView) { + [self setupTickViews]; + [self updateTickHeights]; + } +} + +- (void)removeAllTicks { + for (NSUInteger i = [_ticks count] - 1; i > 0 ; i--) { + [self removeTickAtIndex:i refreshView:NO]; + } + [self removeTickAtIndex:0 refreshView:YES]; + [self setNeedsLayout]; + [self nukeOldTickViews]; } - (void)nukeOldTickViews @@ -830,7 +843,6 @@ - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat CGFloat zeroBased = Xdiff / ([self thumbImageWidth] / 2); CGFloat diffZeroBased = tan(acos(zeroBased)) * zeroBased; CGFloat diff = (1 - diffZeroBased) * ([self thumbImageWidth] / 2); - CGFloat notPopped = [self tickInNotPoppedPositon]; desiredOrigin += diff; // Add because the desired origin is negative the higher it pops. } else{ // Bring down. From 8b194046130b007bf62285d36ced2b6335a4bb45 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 12 Apr 2018 20:10:59 -0600 Subject: [PATCH 19/33] Added App Icon full view. --- HUMSliderSample.xcodeproj/project.pbxproj | 29 ++++++++++++++++++++--- HUMSliderSample/Info.plist | 2 +- HUMSliderSampleTests/Info.plist | 2 +- Library/HUMSlider.h | 6 +++-- Library/HUMSlider.m | 4 +--- 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/HUMSliderSample.xcodeproj/project.pbxproj b/HUMSliderSample.xcodeproj/project.pbxproj index 06d2495..7afad0c 100644 --- a/HUMSliderSample.xcodeproj/project.pbxproj +++ b/HUMSliderSample.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ 9BA867D31A4DF3B900121ED5 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = "Just Hum, LLC"; TargetAttributes = { 9BA867DA1A4DF3B900121ED5 = { @@ -303,20 +303,30 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -344,13 +354,21 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -358,6 +376,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -376,8 +395,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = HUMSliderSample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.justhum.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -387,8 +407,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = HUMSliderSample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.justhum.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -407,6 +428,7 @@ ); INFOPLIST_FILE = HUMSliderSampleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.justhum.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HUMSliderSample.app/HUMSliderSample"; }; @@ -422,6 +444,7 @@ ); INFOPLIST_FILE = HUMSliderSampleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.justhum.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HUMSliderSample.app/HUMSliderSample"; }; diff --git a/HUMSliderSample/Info.plist b/HUMSliderSample/Info.plist index acafe05..6905cc6 100644 --- a/HUMSliderSample/Info.plist +++ b/HUMSliderSample/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.justhum.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/HUMSliderSampleTests/Info.plist b/HUMSliderSampleTests/Info.plist index d3f10fe..ba72822 100644 --- a/HUMSliderSampleTests/Info.plist +++ b/HUMSliderSampleTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.justhum.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index ce3148b..63ea19c 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -76,7 +76,8 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { /** * Inserts a tick at a position. - * @param tick. The tick with the set position between 0 and 1 + * @param tick The tick with the set position between 0 and 1 + * @param refreshView Will update the view this time with the added tick. */ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView; @@ -87,7 +88,8 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { /** * Removes the tick at the given index. . - * @param index. The tick Index with the set position between 0 and 1 + * @param index The tick Index with the set position between 0 and 1 + * @param refreshView Will update the view this time with the removed tick. */ - (void)removeTickAtIndex:(NSUInteger)index refreshView:(BOOL)refreshView; diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 4287601..d0d25f0 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -23,7 +23,7 @@ static CGFloat const HUMTickWidth = 1; // Default Constants -static CGFloat const DefaultThumbPxWidth = 30; //Size of apple's default thumb icon. +static CGFloat const DefaultThumbPxWidth = 31; //Size of apple's default thumb icon. @implementation Tick // Constructor for a tick @@ -819,8 +819,6 @@ - (void)updateTickHeights { } } -#warning - thumbHeight method may do the same thing as self thumbImageWidth. - - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { assert ([self areCustomTicksSetupAndNonNull]); From d8ec3461508f8ca3639238eee7aaab379b6879cb Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Sun, 24 Jun 2018 13:50:50 -0600 Subject: [PATCH 20/33] fixing main thread warnings --- HUMSliderSample.xcodeproj/project.pbxproj | 6 +++++- Library/HUMSlider.m | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/HUMSliderSample.xcodeproj/project.pbxproj b/HUMSliderSample.xcodeproj/project.pbxproj index 7afad0c..4fbedf2 100644 --- a/HUMSliderSample.xcodeproj/project.pbxproj +++ b/HUMSliderSample.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ 9BA867D31A4DF3B900121ED5 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0920; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Just Hum, LLC"; TargetAttributes = { 9BA867DA1A4DF3B900121ED5 = { @@ -307,12 +307,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -358,12 +360,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index d0d25f0..dc5fef3 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -797,8 +797,8 @@ - (void)updateTickHeights { if (![NSThread isMainThread]) { dispatch_async(dispatch_get_main_queue(), ^{ [self updateTickHeights]; - return; }); + return; } CGRect trackRect = [self trackRectForBounds:self.bounds]; @@ -1038,6 +1038,13 @@ - (void)animateTickAtIndex:(NSInteger)index withDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay { + + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self animateTickAtIndex:index toYOrigin:yOrigin withDuration:duration delay:delay]; + }); + return; + } NSLayoutConstraint *constraint = self.allTickBottomConstraints[index]; constraint.constant = yOrigin; From 38336e1cb562fcb6c345888e15c926f277abe618 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Mon, 25 Jun 2018 10:55:06 -0600 Subject: [PATCH 21/33] Removed unnecessary methods --- Library/HUMSlider.m | 270 +++++--------------------------------------- 1 file changed, 29 insertions(+), 241 deletions(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index dc5fef3..6638783 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -188,29 +188,28 @@ - (void)refreshView { - (void)setupTickViews { - if ([self areCustomTicksSetupAndNonNull]) { - [self cleanupConstraintsAfterEvenlySpacedTicks]; - [self setupCustomTickViews]; - [self setupTicksAutoLayoutCustomWidths]; - if (!_enableTicksTransparencyOnIdle) { - [self animateAllTicksInCustomWidths:YES]; - } + [self cleanupConstraintsAfterCustomSpacedTicks]; + + if (!_customTicksEnabled) { + [self setupConsitentlySpacedTickMarks]; } - else { - [self cleanupConstraintsAfterCustomSpacedTicks]; - [self setupSpacedTickViews]; - [self setupTicksAutolayout]; - if (!_enableTicksTransparencyOnIdle) { - [self animateAllTicksIn:YES]; - } + + [self setupCustomTickViews]; + [self setupTicksAutoLayoutCustomWidths]; + if (!_enableTicksTransparencyOnIdle) { + [self animateAllTicksInCustomWidths:YES]; } } -- (void)cleanupConstraintsAfterEvenlySpacedTicks { - self.tickViews = [NSArray new]; // Make sure these get re-initialized - [self clearLayoutConstraintList:_leftTickRightConstraints]; - [self clearLayoutConstraintList:_rightTickLeftConstraints]; - [self clearLayoutConstraintList:_allTickBottomConstraints]; +// Setup evenly spaced ticks per sectionCount +- (void)setupConsitentlySpacedTickMarks { + CGFloat tickDistances = 1 / (self.sectionCount + 1); + CGFloat spacingSoFar = 0; + for (int i = 0 ; i < self.sectionCount ; i++) { + Tick *newTick = [[Tick alloc] initWithPosition:spacingSoFar + tickDistances]; + [self.ticks addObject:newTick]; + spacingSoFar += tickDistances; + } } - (void)cleanupConstraintsAfterCustomSpacedTicks { @@ -236,10 +235,6 @@ - (void)setupCustomTickViews { [self createAndAddBlankTickViewsWithCount:(NSUInteger)[self.ticks count]]; } -- (BOOL)areCustomTicksSetupAndNonNull { - return (self.customTicksEnabled && self.ticks && [self.ticks count] > 0); -} - - (void)createAndAddBlankTickViewsWithCount:(NSUInteger)count { NSMutableArray *tickBuilder = [NSMutableArray array]; for (NSInteger i = 0; i < count; i++) { @@ -263,9 +258,6 @@ - (UIView*)setupCommonTickViewAndAddToSubview { #pragma mark Autolayout - (void)setupTicksAutoLayoutCustomWidths { - - assert([self areCustomTicksSetupAndNonNull]); - //Store the position and bottom constraints for some reason NSMutableArray *bottoms = [NSMutableArray array]; NSMutableArray *middleConstraints = [NSMutableArray array]; @@ -302,81 +294,6 @@ - (void)setupTicksAutoLayoutCustomWidths { [self layoutIfNeeded]; } -- (void)setupTicksAutolayout -{ - assert(![self areCustomTicksSetupAndNonNull]); - - NSMutableArray *bottoms = [NSMutableArray array]; - NSMutableArray *lefts = [NSMutableArray array]; - NSMutableArray *rights = [NSMutableArray array]; - - UIView *middleTick = self.tickViews[self.middleTickIndex]; - [self pinTickWidthAndHeight:middleTick]; - NSLayoutConstraint *midBottom = [self pinTickBottom:middleTick]; - [bottoms addObject:midBottom]; - - // Pin the middle tick to the middle of the slider. - [self addConstraint:[NSLayoutConstraint constraintWithItem:middleTick - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeCenterX - multiplier:1 - constant:0]]; - - for (NSInteger i = 0; i < self.middleTickIndex; i++) { - NSInteger previousLowest = self.middleTickIndex - i; - NSInteger previousHighest = self.middleTickIndex + i; - - NSInteger nextLowest = self.middleTickIndex - (i + 1); - NSInteger nextHighest = self.middleTickIndex + (i + 1); - - UIView *nextToLeft = self.tickViews[nextLowest]; - UIView *nextToRight = self.tickViews[nextHighest]; - - UIView *previousToLeft = self.tickViews[previousLowest]; - UIView *previousToRight = self.tickViews[previousHighest]; - - // Pin widths, heights, and bottoms. - [self pinTickWidthAndHeight:nextToLeft]; - NSLayoutConstraint *leftBottom = [self pinTickBottom:nextToLeft]; - [bottoms insertObject:leftBottom atIndex:0]; - - [self pinTickWidthAndHeight:nextToRight]; - NSLayoutConstraint *rightBottom = [self pinTickBottom:nextToRight]; - [bottoms addObject:rightBottom]; - - // Pin the right of the next leftwards tick to the previous leftwards tick - NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:nextToLeft - attribute:NSLayoutAttributeRight - relatedBy:NSLayoutRelationEqual - toItem:previousToLeft - attribute:NSLayoutAttributeLeft - multiplier:1 - constant:-(self.segmentWidth - HUMTickWidth)]; - [self addConstraint:left]; - [lefts addObject:left]; - - // Pin the left of the next rightwards tick to the previous rightwards tick. - NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:nextToRight - attribute:NSLayoutAttributeLeft - relatedBy:NSLayoutRelationEqual - toItem:previousToRight - attribute:NSLayoutAttributeRight - multiplier:1 - constant:(self.segmentWidth - HUMTickWidth)]; - [self addConstraint:right]; - [rights addObject:right]; - - } - - self.allTickBottomConstraints = bottoms; - self.leftTickRightConstraints = lefts; - self.rightTickLeftConstraints = rights; - - [self layoutIfNeeded]; -} - //Size of the tick itself. - (void)pinTickWidthAndHeight:(UIView *)currentTick { @@ -573,37 +490,12 @@ - (void)layoutSubviews trackRect = [self trackRectForBounds:self.bounds]; [super layoutSubviews]; - if ([self areCustomTicksSetupAndNonNull]) { - [self updateCustomTickConstraintsIfNeeded]; - } - else { - [self updateLeftTickConstraintsIfNeeded]; - } -} -// First method that is called when animating ticks in. -- (void)updateLeftTickConstraintsIfNeeded -{ - assert(![self areCustomTicksSetupAndNonNull]); - - NSLayoutConstraint *firstLeft = self.leftTickRightConstraints.firstObject; - - if (firstLeft.constant != (self.segmentWidth - HUMTickWidth)) { - for (NSInteger i = 0; i < self.middleTickIndex; i++) { - NSLayoutConstraint *leftConstraint = self.rightTickLeftConstraints[i]; - NSLayoutConstraint *rightConstraint = self.leftTickRightConstraints[i]; - leftConstraint.constant = (self.segmentWidth - HUMTickWidth); - rightConstraint.constant = -(self.segmentWidth - HUMTickWidth); - } - - [self layoutIfNeeded]; - } // else good to go. + [self updateCustomTickConstraintsIfNeeded]; } - (void)updateCustomTickConstraintsIfNeeded { - assert([self areCustomTicksSetupAndNonNull]); - NSUInteger tickCount = [self.tickViews count]; NSLayoutConstraint *firstLeft = self.middleTickConstraints.firstObject; @@ -636,7 +528,9 @@ - (void)setValue:(float)value - (void)setSectionCount:(NSUInteger)sectionCount { // Warn the developer that they need to use an odd number of sections. - NSAssert(sectionCount % 2 != 0, @"Must use an odd number of sections!"); + if (_customTicksEnabled) { + NSLog(@"WARNING: Custom ticks are enabled so section count won't do much"); + } _sectionCount = sectionCount; @@ -779,14 +673,8 @@ - (void)setTickColor:(UIColor *)tickColor - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { - if ([self areCustomTicksSetupAndNonNull]) { - [self updateCustomTickConstraintsIfNeeded]; - [self animateAllTicksInCustomWidths:YES]; - } - else { - [self updateLeftTickConstraintsIfNeeded]; - [self animateAllTicksIn:YES]; - } + [self updateCustomTickConstraintsIfNeeded]; + [self animateAllTicksInCustomWidths:YES]; [self popTickIfNeededFromTouch:touch]; @@ -810,19 +698,12 @@ - (void)updateTickHeights { // Animate tick based on the thumb location for (NSInteger i = 0; i < self.tickViews.count; i++) { - if ([self areCustomTicksSetupAndNonNull]) { - [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; - } - else { - [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; - } + [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; } } - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { - assert ([self areCustomTicksSetupAndNonNull]); - UIView *tick = self.tickViews[tickIndex]; NSLayoutConstraint *constraint = self.middleTickConstraints[tickIndex]; @@ -855,32 +736,6 @@ - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat } // else tick is already where it needs to be. } -- (void)animateTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX -{ - assert (![self areCustomTicksSetupAndNonNull]); - - UIView *tick = self.tickViews[tickIndex]; - - CGFloat startSegmentX = (tickIndex * self.segmentWidth) + self.trackXOrigin; - CGFloat endSegmentX = startSegmentX + self.segmentWidth; - - CGFloat desiredOrigin; - if (startSegmentX <= touchX && endSegmentX > touchX) { - // Pop up. - desiredOrigin = [self tickPoppedPosition]; - } else { - // Bring down. - desiredOrigin = [self tickInNotPoppedPositon]; - } - - if (CGRectGetMinY(tick.frame) != desiredOrigin) { - [self animateTickAtIndex:tickIndex - toYOrigin:desiredOrigin - withDuration:self.tickMovementAnimationDuration - delay:0]; - } // else tick is already where it needs to be. -} - - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { [self popTickIfNeededFromTouch:touch]; @@ -898,12 +753,7 @@ - (void)popTickIfNeededFromTouch:(UITouch *)touch // Animate tick based on the thumb location for (NSInteger i = 0; i < self.tickViews.count; i++) { - if ([self areCustomTicksSetupAndNonNull]) { - [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; - } - else { - [self animateTickIfNeededAtIndex:i forTouchX:sliderLoc]; - } + [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; } } @@ -936,19 +786,14 @@ - (void)returnPosition return; } - if ([self areCustomTicksSetupAndNonNull]) { - [self animateAllTicksInCustomWidths:NO]; - } - else { - [self animateAllTicksIn:NO]; - } + [self animateAllTicksInCustomWidths:NO]; } +#pragma mark - Tick Animation + // To Remove - my method for custom widths - (void)animateAllTicksInCustomWidths:(BOOL)inPosition { - assert([self areCustomTicksSetupAndNonNull] == true); - CGFloat origin; CGFloat alpha; @@ -976,63 +821,6 @@ - (void)animateAllTicksInCustomWidths:(BOOL)inPosition } } -#pragma mark - Tick Animation - -- (void)animateAllTicksIn:(BOOL)inPosition -{ - assert([self areCustomTicksSetupAndNonNull] == false); - - CGFloat origin; - CGFloat alpha; - - if (inPosition) { // Ticks are out, coming in - alpha = 1; - origin = [self tickInNotPoppedPositon]; - } else { // Ticks are in, coming out. - alpha = _enableTicksTransparencyOnIdle ? 0 : 1; - origin = [self tickOutPosition]; - } - - [UIView animateWithDuration:self.tickAlphaAnimationDuration - animations:^{ - for (UIView *tick in self.tickViews) { - tick.alpha = alpha; - } - } completion:nil]; - - for (NSInteger i = 0; i <= self.middleTickIndex; i++) { - NSInteger nextHighest = self.middleTickIndex + i; - NSInteger nextLowest = self.middleTickIndex - i; - if (nextHighest == nextLowest) { - // Middle tick - [self animateTickAtIndex:nextHighest - toYOrigin:origin - withDuration:self.tickMovementAnimationDuration - delay:0]; - } else if (nextHighest - nextLowest == 2) { - // Second tick - [self animateTickAtIndex:nextHighest - toYOrigin:origin - withDuration:self.secondTickMovementAndimationDuration - delay:self.nextTickAnimationDelay * i]; - [self animateTickAtIndex:nextLowest - toYOrigin:origin - withDuration:self.secondTickMovementAndimationDuration - delay:self.nextTickAnimationDelay * i]; - } else { - // Rest of ticks - [self animateTickAtIndex:nextHighest - toYOrigin:origin - withDuration:self.tickMovementAnimationDuration - delay:self.nextTickAnimationDelay * i]; - [self animateTickAtIndex:nextLowest - toYOrigin:origin - withDuration:self.tickMovementAnimationDuration - delay:self.nextTickAnimationDelay * i]; - } - } -} - - (void)animateTickAtIndex:(NSInteger)index toYOrigin:(CGFloat)yOrigin withDuration:(NSTimeInterval)duration From bef5dfcf3f0762a97020e59e227b3f040630bcc6 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Sun, 1 Jul 2018 21:16:37 -0600 Subject: [PATCH 22/33] Fixed bugs switching between the two slider types --- Library/HUMSlider.m | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 6638783..59d1dd5 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -3,11 +3,14 @@ // HUMSliderSample // // Created by Ellen Shapiro on 12/26/14. -// Copyright (c) 2014 Just Hum, LLC. All rights reserved. +// Edited by Jeffrey Blayney 6/26/18 +// Copyright (c) 2018 Meatloaf For Everyone LLC // #import "HUMSlider.h" +#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c))) + // Animation Durations static NSTimeInterval const HUMTickAlphaDuration = 0.20; static NSTimeInterval const HUMTickMovementDuration = 0.5; @@ -28,6 +31,7 @@ @implementation Tick // Constructor for a tick - (id)initWithPosition:(CGFloat)position { + position = ROUNDF(position, 1000); // Round to three decimal places NSAssert(position >= 0 && position <= 1, @"Position must be between 0 and 1"); self = [super init]; if (self) { @@ -87,7 +91,9 @@ - (void)commonInit self.nextTickAnimationDelay = HUMTickAnimationDelay; //Private var init - self.ticks = [[NSMutableArray alloc] init]; + if (self.ticks == nil) { + self.ticks = [NSMutableArray new]; + } //These will set the side colors. self.saturatedColor = [UIColor redColor]; @@ -128,10 +134,19 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder return self; } +- (void)setCustomTicksEnabled:(BOOL)customTicksEnabled { + if (customTicksEnabled != self.customTicksEnabled) { + _customTicksEnabled = customTicksEnabled; + self.ticks = [NSMutableArray new]; + } +} + #pragma mark - Ticks - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { + assert(_customTicksEnabled); + if ([self.ticks count] == 0) { [self.ticks addObject:tick]; } @@ -194,6 +209,7 @@ - (void)setupTickViews [self setupConsitentlySpacedTickMarks]; } + [self nukeOldTickViews]; [self setupCustomTickViews]; [self setupTicksAutoLayoutCustomWidths]; if (!_enableTicksTransparencyOnIdle) { @@ -203,7 +219,8 @@ - (void)setupTickViews // Setup evenly spaced ticks per sectionCount - (void)setupConsitentlySpacedTickMarks { - CGFloat tickDistances = 1 / (self.sectionCount + 1); + self.ticks = [NSMutableArray new]; + CGFloat tickDistances = 1.0 / (self.sectionCount + 1); CGFloat spacingSoFar = 0; for (int i = 0 ; i < self.sectionCount ; i++) { Tick *newTick = [[Tick alloc] initWithPosition:spacingSoFar + tickDistances]; @@ -237,7 +254,7 @@ - (void)setupCustomTickViews { - (void)createAndAddBlankTickViewsWithCount:(NSUInteger)count { NSMutableArray *tickBuilder = [NSMutableArray array]; - for (NSInteger i = 0; i < count; i++) { + for (NSUInteger i = 0; i < count; i++) { UIView *tick = [self setupCommonTickViewAndAddToSubview]; [tickBuilder addObject:tick]; } @@ -498,6 +515,10 @@ - (void)updateCustomTickConstraintsIfNeeded { NSUInteger tickCount = [self.tickViews count]; + if (tickCount == 0) { + return; + } + NSLayoutConstraint *firstLeft = self.middleTickConstraints.firstObject; Tick *firstTick = self.ticks[0]; From 2324ead3abc8ae11dda22103ae927f2863dfc8e7 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 08:32:44 -0600 Subject: [PATCH 23/33] Removed copyright as it interferes with the MIT license. Added comments and changed an integer reference. --- Library/HUMSlider.h | 4 +++- Library/HUMSlider.m | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Library/HUMSlider.h b/Library/HUMSlider.h index 63ea19c..a620aae 100644 --- a/Library/HUMSlider.h +++ b/Library/HUMSlider.h @@ -3,7 +3,7 @@ // HUMSliderSample // // Created by Ellen Shapiro on 12/26/14. -// Copyright (c) 2014 Just Hum, LLC. All rights reserved. +// Edited by Jeffrey Blayney 6/26/18 // #import @@ -14,7 +14,9 @@ typedef NS_ENUM(NSUInteger, HUMSliderSide) { }; @interface Tick : NSObject +///Constructor for tick with position between and including 0 and 1 - (id)initWithPosition:(CGFloat)position; +///Position property with position between and including 0 and 1 @property CGFloat position; //Number between 0 and 1 indicating the slider position of the tick. @end diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 59d1dd5..58f9bef 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -4,7 +4,6 @@ // // Created by Ellen Shapiro on 12/26/14. // Edited by Jeffrey Blayney 6/26/18 -// Copyright (c) 2018 Meatloaf For Everyone LLC // #import "HUMSlider.h" @@ -31,7 +30,7 @@ @implementation Tick // Constructor for a tick - (id)initWithPosition:(CGFloat)position { - position = ROUNDF(position, 1000); // Round to three decimal places + position = ROUNDF(position, 1000); // Round to three decimal places to eliminate chances of float inprecision on comparisons. NSAssert(position >= 0 && position <= 1, @"Position must be between 0 and 1"); self = [super init]; if (self) { @@ -222,7 +221,7 @@ - (void)setupConsitentlySpacedTickMarks { self.ticks = [NSMutableArray new]; CGFloat tickDistances = 1.0 / (self.sectionCount + 1); CGFloat spacingSoFar = 0; - for (int i = 0 ; i < self.sectionCount ; i++) { + for (NSUInteger i = 0 ; i < self.sectionCount ; i++) { Tick *newTick = [[Tick alloc] initWithPosition:spacingSoFar + tickDistances]; [self.ticks addObject:newTick]; spacingSoFar += tickDistances; From 534837edde5a156695cd3938ae5ca35a5cc92609 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 12:41:57 -0600 Subject: [PATCH 24/33] Cleanup and bugfixing --- Library/HUMSlider.m | 239 +++++++++++++++++++++----------------------- README.md | 3 +- 2 files changed, 117 insertions(+), 125 deletions(-) diff --git a/Library/HUMSlider.m b/Library/HUMSlider.m index 58f9bef..ca194eb 100644 --- a/Library/HUMSlider.m +++ b/Library/HUMSlider.m @@ -42,15 +42,11 @@ - (id)initWithPosition:(CGFloat)position { @interface HUMSlider () -@property (nonatomic) NSArray *tickViews; -@property (nonatomic) NSArray *allTickBottomConstraints; - -//Constraint storage for evenly spaced tick constraints. -@property (nonatomic) NSArray *leftTickRightConstraints; //FUTURE, use the middleTickConstraints strategy for equal spaced ticks -@property (nonatomic) NSArray *rightTickLeftConstraints; +@property (atomic) NSMutableArray *tickViews; +@property (atomic) NSMutableArray *allTickBottomConstraints; //Constraint storage for dynamically spaced tick constraints. -@property (nonatomic) NSArray *middleTickConstraints; +@property (atomic) NSMutableArray *middleTickConstraints; @property (nonatomic) UIImage *leftTemplate; @property (nonatomic) UIImage *rightTemplate; @@ -78,6 +74,9 @@ - (void)commonInit trackRect = CGRectZero; [self thumbImageWidth]; // Lazy init of initial calc of thumb image width. + self.allTickBottomConstraints = [NSMutableArray array]; + self.middleTickConstraints = [NSMutableArray array]; + self.lowerTicksOnInactiveTouch = true; //default to lowering them. self.customTicksEnabled = false; //default to true self.enableTicksTransparencyOnIdle = true; // keep ticks at all times. @@ -136,7 +135,11 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder - (void)setCustomTicksEnabled:(BOOL)customTicksEnabled { if (customTicksEnabled != self.customTicksEnabled) { _customTicksEnabled = customTicksEnabled; - self.ticks = [NSMutableArray new]; + [self removeAllTicks]; + NSLog(@"INFO: Slider mode changed to customTicksEnabled: %@, all ticks removed", self.customTicksEnabled ? @"true" : @"false"); + } + else { + NSLog(@"Slider mode unchanged, customTicksEnabled was already set to %@", self.customTicksEnabled ? @"true" : @"false"); } } @@ -148,117 +151,93 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { if ([self.ticks count] == 0) { [self.ticks addObject:tick]; + [self setupTickAutoLayoutForIndex:0 withTick:tick refreshView:refreshView]; } else { // Sorted-ly add the tick in the right sorted order. NSUInteger index = [self.ticks count]; for (Tick *tickItr in [self.ticks reverseObjectEnumerator]) { if (tick.position >= tickItr.position) { [self.ticks insertObject:tick atIndex:index]; + [self setupTickAutoLayoutForIndex:index withTick:tick refreshView:refreshView]; break; } index --; } } + [self checkIntegrity]; + if (refreshView) { - [self setupTickViews]; + [self layoutIfNeeded]; [self updateTickHeights]; } } - (void)removeTickAtIndex:(NSUInteger)index refreshView:(BOOL)refreshView { - [_ticks removeObjectAtIndex:index]; + + //remove the tick object itself + [self.ticks removeObjectAtIndex:index]; + + //remove the view and remove tracked constraints, the view removes constraints as part of "removeFromSuperview" + [self removeConstraintFromList:self.middleTickConstraints constraintAtIndex:index]; + [self removeConstraintFromList:self.allTickBottomConstraints constraintAtIndex:index]; + UIView *tickView = [self.tickViews objectAtIndex:index]; + [self.tickViews removeObjectAtIndex:index]; + [tickView removeFromSuperview]; + + [self checkIntegrity]; + if (refreshView) { - [self setupTickViews]; [self updateTickHeights]; + [self setNeedsLayout]; } } - (void)removeAllTicks { - for (NSUInteger i = [_ticks count] - 1; i > 0 ; i--) { + for (NSUInteger i = [self.ticks count] - 1; i > 0 ; i--) { [self removeTickAtIndex:i refreshView:NO]; } - [self removeTickAtIndex:0 refreshView:YES]; - [self setNeedsLayout]; - [self nukeOldTickViews]; + [self removeTickAtIndex:0 refreshView:YES]; // Refresh on last one. + [self layoutIfNeeded]; } -- (void)nukeOldTickViews +- (void)nukeOldTicksAndViews { for (UIView *tick in self.tickViews) { [tick removeFromSuperview]; } - self.tickViews = nil; - self.leftTickRightConstraints = nil; - self.allTickBottomConstraints = nil; - - [self layoutIfNeeded]; -} - -- (void)refreshView { - [self setupTickViews]; -} - -- (void)setupTickViews -{ - [self cleanupConstraintsAfterCustomSpacedTicks]; + self.ticks = [NSMutableArray new]; + self.tickViews = [NSMutableArray new]; + self.middleTickConstraints = [NSMutableArray new]; + self.allTickBottomConstraints = [NSMutableArray new]; - if (!_customTicksEnabled) { - [self setupConsitentlySpacedTickMarks]; - } + [self checkIntegrity]; - [self nukeOldTickViews]; - [self setupCustomTickViews]; - [self setupTicksAutoLayoutCustomWidths]; - if (!_enableTicksTransparencyOnIdle) { - [self animateAllTicksInCustomWidths:YES]; - } + [self layoutIfNeeded]; } // Setup evenly spaced ticks per sectionCount - (void)setupConsitentlySpacedTickMarks { + assert(!self.customTicksEnabled); self.ticks = [NSMutableArray new]; CGFloat tickDistances = 1.0 / (self.sectionCount + 1); CGFloat spacingSoFar = 0; - for (NSUInteger i = 0 ; i < self.sectionCount ; i++) { + for (NSUInteger i = 0 ; i < self.sectionCount; i++) { Tick *newTick = [[Tick alloc] initWithPosition:spacingSoFar + tickDistances]; [self.ticks addObject:newTick]; + [self setupTickAutoLayoutForIndex:i withTick:newTick refreshView:NO]; spacingSoFar += tickDistances; } + [self checkIntegrity]; + [self layoutIfNeeded]; } -- (void)cleanupConstraintsAfterCustomSpacedTicks { - self.tickViews = [NSArray new]; // Make sure these get re-initialized - [self clearLayoutConstraintList:self.middleTickConstraints]; - [self clearLayoutConstraintList:self.allTickBottomConstraints]; -} - -// Disassociate all of the NSLayoutConstraints in the list from the parent view. -- (void)clearLayoutConstraintList:(NSArray*)list { - if (list) { - for (NSLayoutConstraint *constraint in list) { - [self removeConstraint:constraint]; - } - } -} - -- (void)setupSpacedTickViews { - [self createAndAddBlankTickViewsWithCount:(NSUInteger)self.sectionCount]; -} - -- (void)setupCustomTickViews { - [self createAndAddBlankTickViewsWithCount:(NSUInteger)[self.ticks count]]; -} - -- (void)createAndAddBlankTickViewsWithCount:(NSUInteger)count { - NSMutableArray *tickBuilder = [NSMutableArray array]; - for (NSUInteger i = 0; i < count; i++) { - UIView *tick = [self setupCommonTickViewAndAddToSubview]; - [tickBuilder addObject:tick]; - } - - self.tickViews = tickBuilder; +// Helper method to remove a constraint from our tracked constraint lists and our view. +- (void)removeConstraintFromList:(NSMutableArray*)constraintList constraintAtIndex:(CGFloat)index{ + NSLayoutConstraint *constraint = [constraintList objectAtIndex:index]; + [self removeConstraint:constraint]; + [constraintList removeObjectAtIndex:index]; } - (UIView*)setupCommonTickViewAndAddToSubview { @@ -273,41 +252,35 @@ - (UIView*)setupCommonTickViewAndAddToSubview { #pragma mark Autolayout -- (void)setupTicksAutoLayoutCustomWidths { - //Store the position and bottom constraints for some reason - NSMutableArray *bottoms = [NSMutableArray array]; - NSMutableArray *middleConstraints = [NSMutableArray array]; +- (void)setupTickAutoLayoutForIndex:(CGFloat)index withTick:(Tick*)newlyAddedTick refreshView:(BOOL)refreshView { - for (NSInteger i = 0; i < [self.tickViews count]; i++) { - - UIView *currentItem = self.tickViews[i]; - - NSLayoutConstraint *bottomConstraint = [self pinTickBottom:currentItem]; - [self addConstraint:bottomConstraint]; - [bottoms insertObject:bottomConstraint atIndex:i]; - [self pinTickWidthAndHeight:currentItem]; - - Tick *theTickGuy = _ticks[i]; - - double constant = [self tickPixelOffsetFromMiddle:theTickGuy]; - - // Pin the middle tick to the middle of the slider. - NSLayoutConstraint *middle = [NSLayoutConstraint constraintWithItem:currentItem - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeCenterX - multiplier:1 - constant:constant]; - - [self addConstraint:middle]; - [middleConstraints addObject:middle]; - } - - self.allTickBottomConstraints = bottoms; - self.middleTickConstraints = middleConstraints; + UIView *currentItem = [self setupCommonTickViewAndAddToSubview]; + + [self.tickViews insertObject:currentItem atIndex:index]; - [self layoutIfNeeded]; + NSLayoutConstraint *bottomConstraint = [self pinTickBottom:currentItem]; + [self addConstraint:bottomConstraint]; + [self.allTickBottomConstraints insertObject:bottomConstraint atIndex:index]; + [self pinTickWidthAndHeight:currentItem]; + + double constant = [self tickPixelOffsetFromMiddle:newlyAddedTick]; + + // Pin the middle tick to the middle of the slider. + NSLayoutConstraint *middle = [NSLayoutConstraint constraintWithItem:currentItem + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:constant]; + + [self addConstraint:middle]; + [self.middleTickConstraints addObject:middle]; + + [self checkIntegrity]; + + if (refreshView) + [self layoutIfNeeded]; } //Size of the tick itself. @@ -499,6 +472,13 @@ - (void)pinView1Center:(UIView *)view1 toView2Center:(UIView *)view2 } +- (void)checkIntegrity { + // Transitivity + assert([self.middleTickConstraints count] == [self.allTickBottomConstraints count]); + assert([self.allTickBottomConstraints count] == [self.tickViews count]); + assert([self.tickViews count] == [self.ticks count]); +} + #pragma mark - General layout - (void)layoutSubviews @@ -537,6 +517,14 @@ - (void)updateCustomTickConstraintsIfNeeded } } +- (void)refreshView { + if (!self.enableTicksTransparencyOnIdle) { + [self animateAllTicksIn:YES]; + } + [self updateTickHeights]; + [self layoutIfNeeded]; +} + #pragma mark - Overridden Setters - (void)setValue:(float)value @@ -547,15 +535,17 @@ - (void)setValue:(float)value - (void)setSectionCount:(NSUInteger)sectionCount { - // Warn the developer that they need to use an odd number of sections. - if (_customTicksEnabled) { - NSLog(@"WARNING: Custom ticks are enabled so section count won't do much"); - } - _sectionCount = sectionCount; - [self nukeOldTickViews]; - [self setupTickViews]; + if (self.customTicksEnabled) { + NSLog(@"WARNING: Custom ticks are enabled so sectionCount won't work"); + } + else { + [self nukeOldTicksAndViews]; + if (!self.customTicksEnabled) { + [self setupConsitentlySpacedTickMarks]; + } + } } - (void)setMinimumValueImage:(UIImage *)minimumValueImage @@ -683,18 +673,17 @@ - (void)setTickColor:(UIColor *)tickColor _tickColor = tickColor; if (self.tickViews) { for (UIView *tick in self.tickViews) { - tick.backgroundColor = _tickColor; + tick.backgroundColor = self.tickColor; } } } #pragma mark - UIControl touch event tracking -#pragma mark Animate In - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { [self updateCustomTickConstraintsIfNeeded]; - [self animateAllTicksInCustomWidths:YES]; + [self animateAllTicksIn:YES]; [self popTickIfNeededFromTouch:touch]; @@ -702,7 +691,7 @@ - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event } - (void)updateTickHeights { - if (![NSThread isMainThread]) { + if (![NSThread isMainThread]) { // Available to the dev for playback type development, can be called from bg thread. dispatch_async(dispatch_get_main_queue(), ^{ [self updateTickHeights]; }); @@ -722,6 +711,8 @@ - (void)updateTickHeights { } } +#pragma mark Animate In + - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat)touchX { UIView *tick = self.tickViews[tickIndex]; @@ -736,9 +727,9 @@ - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat CGFloat desiredOrigin; if (startSegmentX <= touchX && endSegmentX > touchX) { - // Pop up. + // Pop up and meld tick to slide over the thumb image as it passes by, which can be slow on playback. desiredOrigin = [self tickPoppedPosition]; - CGFloat Xdiff = fabs(touchX - tickDistanceFromLeft);//fmin(fabs(touchX - startSegmentX), fabs(touchX - endSegmentX)); + CGFloat Xdiff = fabs(touchX - tickDistanceFromLeft); //fmin(fabs(touchX - startSegmentX), fabs(touchX - endSegmentX)); CGFloat zeroBased = Xdiff / ([self thumbImageWidth] / 2); CGFloat diffZeroBased = tan(acos(zeroBased)) * zeroBased; CGFloat diff = (1 - diffZeroBased) * ([self thumbImageWidth] / 2); @@ -772,7 +763,7 @@ - (void)popTickIfNeededFromTouch:(UITouch *)touch CGFloat sliderLoc = CGRectGetMidX(thumbRect); // Animate tick based on the thumb location - for (NSInteger i = 0; i < self.tickViews.count; i++) { + for (NSUInteger i = 0; i < self.tickViews.count; i++) { [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; } } @@ -806,13 +797,13 @@ - (void)returnPosition return; } - [self animateAllTicksInCustomWidths:NO]; + [self animateAllTicksIn:NO]; } #pragma mark - Tick Animation // To Remove - my method for custom widths -- (void)animateAllTicksInCustomWidths:(BOOL)inPosition +- (void)animateAllTicksIn:(BOOL)inPosition { CGFloat origin; CGFloat alpha; @@ -847,7 +838,7 @@ - (void)animateTickAtIndex:(NSInteger)index delay:(NSTimeInterval)delay { - if (![NSThread isMainThread]) { + if (![NSThread isMainThread]) { // This can be called by the updateTickHeights method by the dev on the background thread. dispatch_async(dispatch_get_main_queue(), ^{ [self animateTickAtIndex:index toYOrigin:yOrigin withDuration:duration delay:delay]; }); @@ -930,13 +921,15 @@ - (CGFloat)tickPixelOffsetFromMiddle:(Tick*)tick { return constant; } -- (CGFloat)thumbImageWidth // default thumb image is 30 px, +- (CGFloat)thumbImageWidth { double imgThumbImageWidth = self.currentThumbImage.size.width; + //CASE if the thumb image width is set, is nonzero and doesn't match our current var, set the var to the correct value. if (imgThumbImageWidth && imgThumbImageWidth != 0 && imgThumbImageWidth != thumbImageWidth) { thumbImageWidth = imgThumbImageWidth; } - else if (!thumbImageWidth || thumbImageWidth == 0) { // No custom image set, use 30 + //CASE: if it isn't set or is 0, it is wrong - it will use apple's default thumb image size. + else if (!thumbImageWidth || thumbImageWidth == 0) { // No custom image set, use apple's default thumbImageWidth = DefaultThumbPxWidth; } return thumbImageWidth; diff --git a/README.md b/README.md index 74d1c55..81cef83 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ A quick programmatic example of the most common use case: slider.desaturatedColor = [[UIColor redColor] colorWithAlpha:0.5f]; // How many ticks do you want? (Only works if customTicksEnabled == false) - slider.sectionCount = 11; // This should be an odd number. + slider.sectionCount = 11; // What color should the ticks be? slider.tickColor = [UIColor blackColor]; @@ -75,7 +75,6 @@ Full code is available in the sample app included in this repo. ## Usage notes -- The number of ticks **must be odd** - otherwise pretty much all the math for centering things breaks spectacularly. Attempting to add an even number of ticks will cause an assertion failure during development. - If you are using a custom thumb image which has some clear space at the top, use the `pointAdjustmentForCustomThumb` property to compensate for this. - This control defines its own intrinsic content height based on how high the ticks will pop up, but does not define its own intrinsic content width. - Images passed in as min/max images will automatically be set to use `UIImageRenderingModeAlwaysTemplate` in order to facilitate the saturation and desaturation of the image using tint colors. From e486cdfde498d81022bb9a83bdfe9a86da190914 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 12:48:23 -0600 Subject: [PATCH 25/33] Touched up the readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 81cef83..a2f9e89 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ A quick programmatic example of the most common use case: ```objectivec HUMSlider *slider = [[HUMSlider alloc] init]; - // Set the images to be saturated and desaturated - slider.minimumValueImage = [UIImage imageNamed:@"minImage"]; + // Set the images to be saturated and desaturated + slider.minimumValueImage = [UIImage imageNamed:@"minImage"]; slider.maximumValueImage = [UIImage imageNamed:@"maxImage"]; // What color should the image be when the thumb is close to it? @@ -64,14 +64,14 @@ A quick programmatic example of the most common use case: ## Custom Tracking - Simply call the updateTickHeights method regularly if you are programmatically - moving the slider, and want the ticks the same as if the user is moving them. + moving the slider, and want the ticks to appear the same as if the user is moving them. ```objectivec [slider updateTickHeights] ``` -Full code is available in the sample app included in this repo. +Code for constant spaced ticks is available in the sample app included in this repo. ## Usage notes From 25bc0eddb3110dc00031b25c8afd82daddf14fb3 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 13:35:44 -0600 Subject: [PATCH 26/33] Changing double to CGFloat --- HUMSlider/HUMSlider.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index 40e83a9..f9a934a 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -263,7 +263,7 @@ - (void)setupTickAutoLayoutForIndex:(CGFloat)index withTick:(Tick*)newlyAddedTic [self.allTickBottomConstraints insertObject:bottomConstraint atIndex:index]; [self pinTickWidthAndHeight:currentItem]; - double constant = [self tickPixelOffsetFromMiddle:newlyAddedTick]; + CGFloat constant = [self tickPixelOffsetFromMiddle:newlyAddedTick]; // Pin the middle tick to the middle of the slider. NSLayoutConstraint *middle = [NSLayoutConstraint constraintWithItem:currentItem @@ -913,14 +913,14 @@ - (CGFloat)tickPoppedPosition } - (CGFloat)tickPixelOffsetFromMiddle:(Tick*)tick { - double trackWidth = trackRect.size.width - [self thumbImageWidth] + trackRect.origin.x; // :) - double constant = (tick.position * trackWidth) - (trackWidth / 2); + CGFloat trackWidth = trackRect.size.width - [self thumbImageWidth] + trackRect.origin.x; // :) + CGFloat constant = (tick.position * trackWidth) - (trackWidth / 2); return constant; } - (CGFloat)thumbImageWidth { - double imgThumbImageWidth = self.currentThumbImage.size.width; + CGFloat imgThumbImageWidth = self.currentThumbImage.size.width; // CASE if the thumb image width is set, is nonzero and doesn't match our current var, set the var to the correct value. if (imgThumbImageWidth && imgThumbImageWidth != 0 && imgThumbImageWidth != thumbImageWidth) { thumbImageWidth = imgThumbImageWidth; From 5ebf725d9f363cd925d4ab651cb51b53c036587f Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 13:38:01 -0600 Subject: [PATCH 27/33] using self. instead of synthesized --- HUMSlider/HUMSlider.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index f9a934a..2bef58d 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -809,7 +809,7 @@ - (void)animateAllTicksIn:(BOOL)inPosition alpha = 1; origin = [self tickInNotPoppedPositon]; } else { // Ticks are in, coming out. - alpha = _enableTicksTransparencyOnIdle ? 0 : 1; // Transparent if setting is enabed. + alpha = self.enableTicksTransparencyOnIdle ? 0 : 1; // Transparent if setting is enabed. origin = [self tickOutPosition]; } From 5d3858eebfbf6cccbcb1c3544edef49f5fc81911 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 13:51:45 -0600 Subject: [PATCH 28/33] use BOOL not bool --- HUMSlider/HUMSlider.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index 2bef58d..b84088c 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -77,9 +77,9 @@ - (void)commonInit self.allTickBottomConstraints = [NSMutableArray array]; self.middleTickConstraints = [NSMutableArray array]; - self.lowerTicksOnInactiveTouch = true; //default to lowering them. - self.customTicksEnabled = false; //default to true - self.enableTicksTransparencyOnIdle = true; // keep ticks at all times. + self.lowerTicksOnInactiveTouch = YES; // default to lowering them. + self.customTicksEnabled = NO; // default to false + self.enableTicksTransparencyOnIdle = YES; // Only show ticks when user is touching slider // Set default values. self.sectionCount = 9; From 8f0804ac311a623730998d87380f32ce72b89791 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 19:08:44 -0600 Subject: [PATCH 29/33] Fixed index insertion error for middle constraints --- HUMSlider/HUMSlider.m | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index b84088c..1792327 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -166,10 +166,11 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { } [self checkIntegrity]; + [self updateTickHeights]; if (refreshView) { + [self setNeedsLayout]; [self layoutIfNeeded]; - [self updateTickHeights]; } } @@ -275,12 +276,13 @@ - (void)setupTickAutoLayoutForIndex:(CGFloat)index withTick:(Tick*)newlyAddedTic constant:constant]; [self addConstraint:middle]; - [self.middleTickConstraints addObject:middle]; + [self.middleTickConstraints insertObject:middle atIndex:index]; [self checkIntegrity]; - if (refreshView) - [self layoutIfNeeded]; + if (refreshView) { + [self setNeedsLayout]; + } } // Size of the tick itself. @@ -504,7 +506,7 @@ - (void)updateCustomTickConstraintsIfNeeded if (firstLeft.constant != constant) { - for (NSInteger i = 0; i < [self.tickViews count]; i++) { + for (NSUInteger i = 0; i < [self.tickViews count]; i++) { NSLayoutConstraint *middleConstraint = self.middleTickConstraints[i]; Tick *theTick = self.ticks[i]; middleConstraint.constant = [self tickPixelOffsetFromMiddle:theTick]; @@ -519,6 +521,7 @@ - (void)refreshView { [self animateAllTicksIn:YES]; } [self updateTickHeights]; + [self setNeedsLayout]; [self layoutIfNeeded]; } @@ -714,7 +717,7 @@ - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat { UIView *tick = self.tickViews[tickIndex]; - NSLayoutConstraint *constraint = self.middleTickConstraints[tickIndex]; + NSLayoutConstraint *constraint = [self.middleTickConstraints objectAtIndex:tickIndex]; CGFloat tickDistanceFromLeft = (trackRect.size.width / 2) + (constraint.constant) + trackRect.origin.x; CGFloat thumbSliderRadius = [self thumbImageWidth] / 2; From 82b4ba6a9f8e031e7d823114a712f7740ca7e19f Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 20:54:21 -0600 Subject: [PATCH 30/33] Removing global track Rect --- HUMSlider/HUMSlider.m | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index 1792327..cf1ae3f 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -64,14 +64,12 @@ @interface HUMSlider () @implementation HUMSlider { CGFloat thumbImageWidth; // Reference to last computed thumb width. - CGRect trackRect; // store the track width from the layoutSubviews. } #pragma mark - Init - (void)commonInit { - trackRect = CGRectZero; [self thumbImageWidth]; // Lazy init of initial calc of thumb image width. self.allTickBottomConstraints = [NSMutableArray array]; @@ -485,7 +483,7 @@ - (void)checkIntegrity { - (void)layoutSubviews { - trackRect = [self trackRectForBounds:self.bounds]; + CGRect trackRect = [self trackRectForBounds:self.bounds]; [super layoutSubviews]; @@ -704,7 +702,7 @@ - (void)updateTickHeights { value:self.value]; CGFloat sliderLoc = CGRectGetMidX(thumbRect); - + // Animate tick based on the thumb location for (NSInteger i = 0; i < self.tickViews.count; i++) { [self animateCustomTickIfNeededAtIndex:i forTouchX:sliderLoc]; @@ -719,6 +717,7 @@ - (void)animateCustomTickIfNeededAtIndex:(NSInteger)tickIndex forTouchX:(CGFloat NSLayoutConstraint *constraint = [self.middleTickConstraints objectAtIndex:tickIndex]; + CGRect trackRect = [self trackRectForBounds:self.bounds]; CGFloat tickDistanceFromLeft = (trackRect.size.width / 2) + (constraint.constant) + trackRect.origin.x; CGFloat thumbSliderRadius = [self thumbImageWidth] / 2; @@ -847,7 +846,6 @@ - (void)animateTickAtIndex:(NSInteger)index NSLayoutConstraint *constraint = self.allTickBottomConstraints[index]; constraint.constant = yOrigin; - [UIView animateWithDuration:duration delay:delay usingSpringWithDamping:0.6f @@ -916,6 +914,7 @@ - (CGFloat)tickPoppedPosition } - (CGFloat)tickPixelOffsetFromMiddle:(Tick*)tick { + CGRect trackRect = [self trackRectForBounds:self.bounds]; CGFloat trackWidth = trackRect.size.width - [self thumbImageWidth] + trackRect.origin.x; // :) CGFloat constant = (tick.position * trackWidth) - (trackWidth / 2); return constant; From 519f69250da8819808af34e83be5722734ff0833 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Thu, 5 Jul 2018 20:57:02 -0600 Subject: [PATCH 31/33] Removing unused var --- HUMSlider/HUMSlider.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index cf1ae3f..0c888df 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -483,8 +483,6 @@ - (void)checkIntegrity { - (void)layoutSubviews { - CGRect trackRect = [self trackRectForBounds:self.bounds]; - [super layoutSubviews]; [self updateCustomTickConstraintsIfNeeded]; From 51a6e1218e59ae1b4e870d59b0e117ae952cb956 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Sun, 26 Aug 2018 20:54:21 -0600 Subject: [PATCH 32/33] Fixed issue where the tick doesn't pop or show on initial addition --- HUMSlider/HUMSlider.m | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index 0c888df..28e9600 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -167,8 +167,7 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { [self updateTickHeights]; if (refreshView) { - [self setNeedsLayout]; - [self layoutIfNeeded]; + [self refreshView]; } } @@ -279,6 +278,7 @@ - (void)setupTickAutoLayoutForIndex:(CGFloat)index withTick:(Tick*)newlyAddedTic [self checkIntegrity]; if (refreshView) { + [self updateConstraints]; [self setNeedsLayout]; } } @@ -844,15 +844,17 @@ - (void)animateTickAtIndex:(NSInteger)index NSLayoutConstraint *constraint = self.allTickBottomConstraints[index]; constraint.constant = yOrigin; - [UIView animateWithDuration:duration - delay:delay - usingSpringWithDamping:0.6f - initialSpringVelocity:0.0f - options:UIViewAnimationOptionCurveLinear - animations:^{ - [self layoutIfNeeded]; - } - completion:nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:duration + delay:delay + usingSpringWithDamping:0.6f + initialSpringVelocity:0.0f + options:UIViewAnimationOptionCurveLinear + animations:^{ + [self layoutIfNeeded]; + } + completion:nil]; + }); } #pragma mark - Calculation helpers From 3db2dac203d4ab40cafc19ab703fa5a1f4acf311 Mon Sep 17 00:00:00 2001 From: Jeffrey Blayney Date: Sun, 26 Aug 2018 21:03:10 -0600 Subject: [PATCH 33/33] Real fix for a transparency issue --- HUMSlider/HUMSlider.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HUMSlider/HUMSlider.m b/HUMSlider/HUMSlider.m index 28e9600..80bc38f 100644 --- a/HUMSlider/HUMSlider.m +++ b/HUMSlider/HUMSlider.m @@ -167,7 +167,7 @@ - (void)addTick:(Tick*)tick willRefreshView:(BOOL)refreshView { [self updateTickHeights]; if (refreshView) { - [self refreshView]; + [self layoutSubviews]; } } @@ -241,7 +241,7 @@ - (void)removeConstraintFromList:(NSMutableArray*)constraintList constraintAtInd - (UIView*)setupCommonTickViewAndAddToSubview { UIView *tick = [[UIView alloc] init]; tick.backgroundColor = self.tickColor; - tick.alpha = 0; + tick.alpha = _enableTicksTransparencyOnIdle ? 0 : 1; tick.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:tick]; [self sendSubviewToBack:tick];