Skip to content

Commit

Permalink
Fixes #24: Label vertical animations control
Browse files Browse the repository at this point in the history
  • Loading branch information
Xavier Schott committed Feb 13, 2017
1 parent ae14632 commit 24f9ca4
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 50 deletions.
3 changes: 3 additions & 0 deletions TGPControls/TGPCamelLabels.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ IB_DESIGNABLE
@property (nonatomic) IBInspectable CGFloat offCenter;
@property (nonatomic) IBInspectable NSInteger insets;

@property (nonatomic) IBInspectable NSInteger emphasisLayout;
@property (nonatomic) IBInspectable NSInteger regularLayout;

@end
3 changes: 2 additions & 1 deletion TGPControls/TGPCamelLabels.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ @implementation TGPCamelLabels
@dynamic downFontColor;
@dynamic offCenter;
@dynamic insets;

@dynamic emphasisLayout;
@dynamic regularLayout;
@end
17 changes: 15 additions & 2 deletions TGPControls/TGPCamelLabels7.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,25 @@
@property (nonatomic, strong) NSArray * names; // Will dictate the number of ticks
@property (nonatomic, assign) NSTimeInterval animationDuration;

@property (nonatomic, assign) BOOL animate; // Make the labels animate when selected

// Label off-center to the left and right of the slider, expressed in label width. 0: none, -1/2 half out, 1/2 half in
@property (nonatomic, assign) CGFloat offCenter;

// Label margins to the left and right of the slider
@property (nonatomic, assign) NSInteger insets;

// Where should emphasized labels be drawn (10: centerY, 3: top, 4: bottom)
// By default, emphasized labels are animated towards the top of the frame.
// This creates the dock effect (camel). They can also be centered vertically, or move down (reverse effect).
@property (nonatomic) IBInspectable NSInteger emphasisLayout;

// Where should regular labels be drawn (10: centerY, 3: top, 4: bottom)
// By default, emphasized labels are animated towards the bottom of the frame.
// This creates the dock effect (camel). They can also be centered vertically, or move up (reverse effect).
@property (nonatomic) IBInspectable NSInteger regularLayout;

#pragma mark IBInspectable adapters

@property (nonatomic) NSLayoutAttribute emphasisLayoutAttribute;
@property (nonatomic) NSLayoutAttribute regularLayoutAttribute;

@end
154 changes: 107 additions & 47 deletions TGPControls/TGPCamelLabels7.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@

@interface TGPCamelLabels7()
@property (nonatomic, assign) NSUInteger lastValue;
@property (nonatomic, retain) NSMutableArray * upLabels;
@property (nonatomic, retain) NSMutableArray * dnLabels;
@property (nonatomic, retain) NSMutableArray * emphasizedLabels;
@property (nonatomic, retain) NSMutableArray * regularLabels;
@end

@implementation TGPCamelLabels7
Expand Down Expand Up @@ -103,13 +103,49 @@ - (void)setInsets:(NSInteger)insets {
[self layoutTrack];
}

- (void)setEmphasisLayout:(NSInteger)emphasisLayout {
_emphasisLayout = ([self validAttribute:emphasisLayout]
? emphasisLayout
: NSLayoutAttributeTop);
[self layoutTrack];
}

- (void)setRegularLayout:(NSInteger)regularLayout {
_regularLayout = ([self validAttribute:regularLayout]
? regularLayout
: NSLayoutAttributeBottom);
[self layoutTrack];
}

// NSArray<NSString*>
- (void)setNames:(NSArray *)names {
NSAssert(names.count > 0, @"names.count");
_names = names;
[self layoutTrack];
}

#pragma mark IBInspectable adapters

- (NSLayoutAttribute)emphasisLayoutAttribute {
return ([self validAttribute:_emphasisLayout]
? _emphasisLayout
: NSLayoutAttributeTop);
}

- (void)setEmphasisLayoutAttribute:(NSLayoutAttribute)emphasisLayoutAttribute {
self.emphasisLayout = emphasisLayoutAttribute;
}

- (NSLayoutAttribute)regularLayoutAttribute {
return ([self validAttribute:_regularLayout]
? _regularLayout
: NSLayoutAttributeBottom);
}

- (void)setRegularLayoutAttribute:(NSLayoutAttribute)regularLayoutAttribute {
self.regularLayout = regularLayoutAttribute;
}

#pragma mark UIView

- (id)initWithCoder:(NSCoder *)aDecoder {
Expand Down Expand Up @@ -160,16 +196,18 @@ - (void)initProperties {
_downFontSize = 12;
_downFontColor = nil;

_upLabels = [NSMutableArray array];
_dnLabels = [NSMutableArray array];
_emphasizedLabels = [NSMutableArray array];
_regularLabels = [NSMutableArray array];

_lastValue = NSNotFound; // Never tapped
_animationDuration = 0.15;

_animate = YES;
_offCenter = 0.0;
_insets = 0;

_emphasisLayout = NSLayoutAttributeTop;
_regularLayout = NSLayoutAttributeBottom;

[self layoutTrack];
}

Expand All @@ -183,22 +221,22 @@ - (void)debugNames:(unsigned int)count {
}

- (void)layoutTrack {
for( UIView * view in self.upLabels) {
for( UIView * view in self.emphasizedLabels) {
[view removeFromSuperview];
}
[self.upLabels removeAllObjects];
for( UIView * view in self.dnLabels) {
[self.emphasizedLabels removeAllObjects];
for( UIView * view in self.regularLabels) {
[view removeFromSuperview];
}
[self.dnLabels removeAllObjects];
[self.regularLabels removeAllObjects];

const NSUInteger count = self.names.count;
if( count > 0) {
CGFloat centerX = (self.bounds.size.width - ((count - 1) * self.ticksDistance))/2.0;
const CGFloat centerY = self.bounds.size.height / 2.0;
for(NSString * name in self.names) {
UILabel * upLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self.upLabels addObject:upLabel];
[self.emphasizedLabels addObject:upLabel];
upLabel.text = name;
upLabel.font = ((self.upFontName != nil)
? [UIFont fontWithName:self.upFontName size:self.upFontSize]
Expand All @@ -217,7 +255,7 @@ - (void)layoutTrack {
[self addSubview:upLabel];

UILabel * dnLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self.dnLabels addObject:dnLabel];
[self.regularLabels addObject:dnLabel];
dnLabel.text = name;
dnLabel.font = ((self.downFontName != nil)
? [UIFont fontWithName:self.downFontName size:self.downFontSize]
Expand All @@ -239,10 +277,10 @@ - (void)layoutTrack {

// Fix left and right label, if there are at least 2 labels
if( [self.names count] > 1) {
[self insetView:[self.upLabels firstObject] withInset:self.insets withMultiplier:self.offCenter];
[self insetView:[self.upLabels lastObject] withInset:-self.insets withMultiplier:-self.offCenter];
[self insetView:[self.dnLabels firstObject] withInset:self.insets withMultiplier:self.offCenter];
[self insetView:[self.dnLabels lastObject] withInset:-self.insets withMultiplier:-self.offCenter];
[self insetView:[self.emphasizedLabels firstObject] withInset:self.insets withMultiplier:self.offCenter];
[self insetView:[self.emphasizedLabels lastObject] withInset:-self.insets withMultiplier:-self.offCenter];
[self insetView:[self.regularLabels firstObject] withInset:self.insets withMultiplier:self.offCenter];
[self insetView:[self.regularLabels lastObject] withInset:-self.insets withMultiplier:-self.offCenter];
}

[self dockEffect:0.0];
Expand All @@ -260,7 +298,7 @@ - (void) insetView:(UIView*)view withInset:(NSInteger)inset withMultiplier:(CGFl

- (void)dockEffect:(NSTimeInterval)duration
{
const NSUInteger up = self.value;
const NSUInteger emphasized = self.value;

// Unlike the National Parks from which it is inspired, this Dock Effect
// does not abruptly change from BOLD to plain. Instead, we have 2 sets of
Expand All @@ -270,24 +308,32 @@ - (void)dockEffect:(NSTimeInterval)duration
// - high to low
// Each animation picks up where the previous left off
void (^moveBlock)() = ^void() {
// Bring almost all down
[self.upLabels enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if( up != idx) {
[self moveDown:obj withAlpha:0.f];
// De-emphasize almost all
[self.emphasizedLabels enumerateObjectsUsingBlock:^(UILabel * label, NSUInteger idx, BOOL *stop) {
if( emphasized != idx) {
[self verticalAlign:label
alpha:0
attribute:self.regularLayoutAttribute];
}
}];
[self.dnLabels enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if( up != idx) {
[self moveDown:obj withAlpha:1.f];
[self.regularLabels enumerateObjectsUsingBlock:^(UILabel * label, NSUInteger idx, BOOL *stop) {
if( emphasized != idx) {
[self verticalAlign:label
alpha:1
attribute:self.regularLayoutAttribute];
}
}];

// Bring the selection up
if(up < [self.upLabels count]) {
[self moveUp:[self.upLabels objectAtIndex:up] withAlpha:1.f];
// Emphasize the selection
if(emphasized < [self.emphasizedLabels count]) {
[self verticalAlign:[self.emphasizedLabels objectAtIndex:emphasized]
alpha:1
attribute:self.emphasisLayoutAttribute];
}
if(up < [self.dnLabels count]) {
[self moveUp:[self.dnLabels objectAtIndex:up] withAlpha:0.f];
if(emphasized < [self.regularLabels count]) {
[self verticalAlign:[self.regularLabels objectAtIndex:emphasized]
alpha:0
attribute:self.emphasisLayoutAttribute];
}
};

Expand All @@ -303,28 +349,42 @@ - (void)dockEffect:(NSTimeInterval)duration
}
}

- (void)moveDown:(UIView*)aView withAlpha:(CGFloat) alpha
{
if (self.animate) {
aView.frame = ({
CGRect frame = aView.frame;
frame.origin.y = self.bounds.size.height - frame.size.height;
frame;
});
}
[aView setAlpha:alpha];
- (BOOL)validAttribute:(NSLayoutAttribute)attribute {
NSArray * validAttributes = @[
@(NSLayoutAttributeTop), // 3
@(NSLayoutAttributeCenterY), // 10
@(NSLayoutAttributeBottom) // 4
];
BOOL valid = [validAttributes containsObject:@(attribute)];
return valid;
}

- (void)moveUp:(UIView*)aView withAlpha:(CGFloat) alpha
{
if (self.animate) {
aView.frame = ({
CGRect frame = aView.frame;
frame.origin.y = 0;
frame;
});
- (void)verticalAlign:(UIView *)aView alpha:(CGFloat) alpha attribute:(NSLayoutAttribute) layout {
switch(layout) {
case NSLayoutAttributeTop:
aView.frame = ({
CGRect frame = aView.frame;
frame.origin.y = 0;
frame;
});
break;

case NSLayoutAttributeBottom:
aView.frame = ({
CGRect frame = aView.frame;
frame.origin.y = self.bounds.size.height - frame.size.height;
frame;
});
break;

default: // NSLayoutAttributeCenterY
aView.frame = ({
CGRect frame = aView.frame;
frame.origin.y = (self.bounds.size.height - frame.size.height) / 2;
frame;
});
}
[aView setAlpha:alpha];
aView.alpha = alpha;
}

#pragma mark - TGPControlsTicksProtocol
Expand Down

0 comments on commit 24f9ca4

Please sign in to comment.