Skip to content

Commit

Permalink
Add MLLeft and MLRight types to Objective-C [ObjC]
Browse files Browse the repository at this point in the history
  • Loading branch information
cbpowell committed Jun 11, 2017
1 parent b1a55ee commit 9f6916b
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 12 deletions.
6 changes: 5 additions & 1 deletion Sources/ObjC/MarqueeLabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ typedef NS_ENUM(NSUInteger, MarqueeType) {
/** Continuously scrolls left (with a pause at the original position if animationDelay is set). See the `trailingBuffer` property to define a spacing between the repeating strings.*/
MLContinuous = 2,
/** Continuously scrolls right (with a pause at the original position if animationDelay is set). See the `trailingBuffer` property to define a spacing between the repeating strings.*/
MLContinuousReverse = 3
MLContinuousReverse = 3,
/** Scrolls left first, then does not return to the original position. */
MLLeft = 4,
/** Scrolls right first, then does not return to the original position. */
MLRight = 5
};


Expand Down
95 changes: 84 additions & 11 deletions Sources/ObjC/MarqueeLabel.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
// iOS Version check for iOS 8.0.0
#define SYSTEM_VERSION_IS_8_0_X ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"8.0"])

// Define "a long time" for MLLeft and MLRight types
#define CGFLOAT_LONG_DURATION 60*60*24*365 // One year in seconds

// Helpers
@interface GradientSetupAnimation : CABasicAnimation
@end
Expand Down Expand Up @@ -332,6 +335,7 @@ - (void)updateSublabelAndBeginScroll:(BOOL)beginScroll {
switch (self.marqueeType) {
case MLContinuousReverse:
case MLRightLeft:
case MLRight:
CGRectDivide(self.bounds, &unusedFrame, &labelFrame, self.leadingBuffer, CGRectMaxXEdge);
labelFrame = CGRectIntegral(labelFrame);
break;
Expand Down Expand Up @@ -388,6 +392,7 @@ - (void)updateSublabelAndBeginScroll:(BOOL)beginScroll {
}

case MLRightLeft:
case MLRight:
{
self.homeLabelFrame = CGRectIntegral(CGRectMake(self.bounds.size.width - (expectedLabelSize.width + self.leadingBuffer), 0.0f, expectedLabelSize.width, self.bounds.size.height));
self.awayOffset = (expectedLabelSize.width + self.trailingBuffer + self.leadingBuffer) - self.bounds.size.width;
Expand All @@ -408,6 +413,7 @@ - (void)updateSublabelAndBeginScroll:(BOOL)beginScroll {
}

case MLLeftRight:
case MLLeft:
{
self.homeLabelFrame = CGRectIntegral(CGRectMake(self.leadingBuffer, 0.0f, expectedLabelSize.width, self.bounds.size.height));
self.awayOffset = self.bounds.size.width - (expectedLabelSize.width + self.leadingBuffer + self.trailingBuffer);
Expand Down Expand Up @@ -513,6 +519,10 @@ - (void)beginScrollWithDelay:(BOOL)delay {
case MLContinuousReverse:
[self scrollContinuousWithInterval:self.animationDuration after:(delay ? self.animationDelay : 0.0)];
break;
case MLLeft:
case MLRight:
[self scrollAwayWithInterval:self.animationDuration delayAmount:(delay ? self.animationDelay : 0.0) shouldReturn:NO];
break;
default:
[self scrollAwayWithInterval:self.animationDuration];
break;
Expand All @@ -535,10 +545,10 @@ - (void)scrollAwayWithInterval:(NSTimeInterval)interval {
}

- (void)scrollAwayWithInterval:(NSTimeInterval)interval delay:(BOOL)delay {
[self scrollAwayWithInterval:interval delayAmount:(delay ? self.animationDelay : 0.0)];
[self scrollAwayWithInterval:interval delayAmount:(delay ? self.animationDelay : 0.0) shouldReturn:YES];
}

- (void)scrollAwayWithInterval:(NSTimeInterval)interval delayAmount:(NSTimeInterval)delayAmount {
- (void)scrollAwayWithInterval:(NSTimeInterval)interval delayAmount:(NSTimeInterval)delayAmount shouldReturn:(BOOL)shouldReturn {
// Check for conditions which would prevent scrolling
if (![self labelReadyForScroll]) {
return;
Expand All @@ -554,7 +564,7 @@ - (void)scrollAwayWithInterval:(NSTimeInterval)interval delayAmount:(NSTimeInter
[CATransaction begin];

// Set Duration
[CATransaction setAnimationDuration:(2.0 * (delayAmount + interval))];
[CATransaction setAnimationDuration:(!shouldReturn ? CGFLOAT_MAX : 2.0 * (delayAmount + interval))];

// Create animation for gradient, if needed
if (self.fadeLength != 0.0f) {
Expand All @@ -580,7 +590,7 @@ - (void)scrollAwayWithInterval:(NSTimeInterval)interval delayAmount:(NSTimeInter
if (self.window && ![weakSelf.subLabel.layer animationForKey:@"position"]) {
// Begin again, if conditions met
if (weakSelf.labelShouldScroll && !weakSelf.tapToScroll && !weakSelf.holdScrolling) {
[weakSelf scrollAwayWithInterval:interval delayAmount:delayAmount];
[weakSelf scrollAwayWithInterval:interval delayAmount:delayAmount shouldReturn:shouldReturn];
}
}
};
Expand All @@ -589,11 +599,25 @@ - (void)scrollAwayWithInterval:(NSTimeInterval)interval delayAmount:(NSTimeInter
// Create animation for position
CGPoint homeOrigin = self.homeLabelFrame.origin;
CGPoint awayOrigin = MLOffsetCGPoint(self.homeLabelFrame.origin, self.awayOffset);
NSArray *values = @[[NSValue valueWithCGPoint:homeOrigin], // Initial location, home
[NSValue valueWithCGPoint:homeOrigin], // Initial delay, at home
[NSValue valueWithCGPoint:awayOrigin], // Animation to away
[NSValue valueWithCGPoint:awayOrigin], // Delay at away
[NSValue valueWithCGPoint:homeOrigin]]; // Animation to home

NSArray *values = nil;
switch (self.marqueeType) {
case MLLeft:
case MLRight:
values = @[[NSValue valueWithCGPoint:homeOrigin], // Initial location, home
[NSValue valueWithCGPoint:homeOrigin], // Initial delay, at home
[NSValue valueWithCGPoint:awayOrigin], // Animation to away
[NSValue valueWithCGPoint:awayOrigin]]; // Delay at away
break;

default:
values = @[[NSValue valueWithCGPoint:homeOrigin], // Initial location, home
[NSValue valueWithCGPoint:homeOrigin], // Initial delay, at home
[NSValue valueWithCGPoint:awayOrigin], // Animation to away
[NSValue valueWithCGPoint:awayOrigin], // Delay at away
[NSValue valueWithCGPoint:homeOrigin]]; // Animation to home
break;
}

CAKeyframeAnimation *awayAnim = [self keyFrameAnimationForProperty:@"position"
values:values
Expand Down Expand Up @@ -741,6 +765,7 @@ - (void)applyGradientMaskForFadeLength:(CGFloat)fadeLength animated:(BOOL)animat
switch (self.marqueeType) {
case MLContinuousReverse:
case MLRightLeft:
case MLRight:
adjustedColors = @[(trailingFadeNeeded ? transparent : opaque),
opaque,
opaque,
Expand Down Expand Up @@ -807,8 +832,7 @@ - (CAKeyframeAnimation *)keyFrameAnimationForGradientFadeLength:(CGFloat)fadeLen
case MLRightLeft:
// Calculate total animation duration
totalDuration = 2.0 * (delayAmount + interval);
keyTimes = @[
@(0.0), // 1) Initial gradient
keyTimes = @[@(0.0), // 1) Initial gradient
@(delayAmount/totalDuration), // 2) Begin of LE fade-in, just as scroll away starts
@((delayAmount + 0.4)/totalDuration), // 3) End of LE fade in [LE fully faded]
@((delayAmount + interval - 0.4)/totalDuration), // 4) Begin of TE fade out, just before scroll away finishes
Expand All @@ -819,6 +843,17 @@ - (CAKeyframeAnimation *)keyFrameAnimationForGradientFadeLength:(CGFloat)fadeLen
@(1.0)]; // 9) End of LE fade out, just as scroll home finishes
break;

case MLLeft:
case MLRight:
// Calculate total animation duration
totalDuration = CGFLOAT_MAX;
keyTimes = @[@(0.0), // 1) Initial gradient
@(delayAmount/totalDuration), // 2) Begin of LE fade-in, just as scroll away starts
@((delayAmount + 0.4)/totalDuration), // 3) End of LE fade in [LE fully faded]
@((delayAmount + interval - 0.4)/totalDuration), // 4) Begin of TE fade out, just before scroll away finishes
@((delayAmount + interval)/totalDuration), // 5) End of TE fade out [TE fade removed]
@(1.0)];
break;
case MLContinuousReverse:
default:
// Calculate total animation duration
Expand Down Expand Up @@ -858,6 +893,17 @@ - (CAKeyframeAnimation *)keyFrameAnimationForGradientFadeLength:(CGFloat)fadeLen
];
break;

case MLRight:
values = @[
(currentValues ? currentValues : @[transp, opaque, opaque, opaque]), // 1)
@[transp, opaque, opaque, opaque], // 2)
@[transp, opaque, opaque, transp], // 3)
@[transp, opaque, opaque, transp], // 4)
@[opaque, opaque, opaque, transp], // 5)
@[opaque, opaque, opaque, transp], // 6)
];
break;

case MLRightLeft:
values = @[
(currentValues ? currentValues : @[transp, opaque, opaque, opaque]), // 1)
Expand All @@ -883,6 +929,17 @@ - (CAKeyframeAnimation *)keyFrameAnimationForGradientFadeLength:(CGFloat)fadeLen
];
break;

case MLLeft:
values = @[
(currentValues ? currentValues : @[opaque, opaque, opaque, transp]), // 1)
@[opaque, opaque, opaque, transp], // 2)
@[transp, opaque, opaque, transp], // 3)
@[transp, opaque, opaque, transp], // 4)
@[transp, opaque, opaque, opaque], // 5)
@[transp, opaque, opaque, opaque], // 6)
];
break;

case MLLeftRight:
default:
values = @[
Expand Down Expand Up @@ -938,6 +995,22 @@ - (CAKeyframeAnimation *)keyFrameAnimationForProperty:(NSString *)property

break;

case MLLeft:
case MLRight:
NSAssert(values.count == 4, @"Incorrect number of values passed for MLLeft-type animation");
totalDuration = CGFLOAT_MAX;
// Set up keyTimes
animation.keyTimes = @[@(0.0), // Initial location, home
@(delayAmount/totalDuration), // Initial delay, at home
@((delayAmount + interval)/totalDuration), // Animation to away
@(1.0)]; // Animation to home

animation.timingFunctions = @[timingFunction,
timingFunction,
timingFunction];

break;

// MLContinuous
// MLContinuousReverse
default:
Expand Down

0 comments on commit 9f6916b

Please sign in to comment.