diff --git a/CBAutoScrollLabel/CBAutoScrollLabel.h b/CBAutoScrollLabel/CBAutoScrollLabel.h index b283704..ed5eec2 100644 --- a/CBAutoScrollLabel/CBAutoScrollLabel.h +++ b/CBAutoScrollLabel/CBAutoScrollLabel.h @@ -42,7 +42,7 @@ typedef enum { @property (nonatomic, strong) UIFont *font; @property (nonatomic, strong) UIColor *shadowColor; @property (nonatomic) CGSize shadowOffset; -@property (nonatomic) UITextAlignment textAlignment; // only applies when not auto-scrolling +@property (nonatomic) NSTextAlignment textAlignment; // only applies when not auto-scrolling /** * Lays out the scrollview contents, enabling text scrolling if the text will be clipped. diff --git a/CBAutoScrollLabel/CBAutoScrollLabel.m b/CBAutoScrollLabel/CBAutoScrollLabel.m index 0082068..c9da3a2 100644 --- a/CBAutoScrollLabel/CBAutoScrollLabel.m +++ b/CBAutoScrollLabel/CBAutoScrollLabel.m @@ -12,7 +12,7 @@ #import "CBAutoScrollLabel.h" #import -#import "SimpleAttributedLabel.h" +#import "MOScrollView.h" #define kLabelCount 2 // pixel buffer space between scrolling label @@ -28,15 +28,17 @@ static void each_object(NSArray *objects, void (^block)(id object)) } // shortcut to change each label attribute value -#define EACH_LABEL(ATTR, VALUE) each_object(self.labels, ^(SimpleAttributedLabel *label) { label.ATTR = VALUE; }); +#define EACH_LABEL(ATTR, VALUE) each_object(self.labels, ^(UILabel *label) { label.ATTR = VALUE; }); @interface CBAutoScrollLabel () { BOOL _isScrolling; + dispatch_source_t _timer1; + dispatch_source_t _timer2; } @property (nonatomic, strong) NSArray *labels; -@property (strong, nonatomic, readonly) SimpleAttributedLabel *mainLabel; -@property (nonatomic, strong) UIScrollView *scrollView; +@property (strong, nonatomic, readonly) UILabel *mainLabel; +@property (nonatomic, strong) MOScrollView *scrollView; @end @@ -79,7 +81,7 @@ - (void)commonInit NSMutableSet *labelSet = [[NSMutableSet alloc] initWithCapacity:kLabelCount]; for (int index = 0 ; index < kLabelCount ; ++index) { - SimpleAttributedLabel *label = [[SimpleAttributedLabel alloc] init]; + UILabel *label = [[UILabel alloc] init]; //label.textColor = [UIColor whiteColor]; label.backgroundColor = [UIColor clearColor]; @@ -99,11 +101,11 @@ - (void)commonInit #endif // default values - _scrollDirection = CBAutoScrollDirectionLeft; + _scrollDirection = !APP_IS_RTL ? CBAutoScrollDirectionLeft : CBAutoScrollDirectionRight; _scrollSpeed = kDefaultPixelsPerSecond; _pauseInterval = kDefaultPauseTime; _labelSpacing = kDefaultLabelBufferSpace; - self.textAlignment = UITextAlignmentLeft; + self.textAlignment = NSTextAlignmentLeft; self.animationOptions = UIViewAnimationOptionCurveEaseIn; self.scrollView.showsVerticalScrollIndicator = NO; self.scrollView.showsHorizontalScrollIndicator = NO; @@ -125,6 +127,7 @@ - (void)dealloc - (void)setFrame:(CGRect)frame { [super setFrame:frame]; + [self refreshLabels]; [self applyGradientMaskForFadeLength:self.fadeLength enableLeft:_isScrolling]; } @@ -134,7 +137,7 @@ - (UIScrollView *)scrollView { if (_scrollView == nil) { - _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; + _scrollView = [[MOScrollView alloc] initWithFrame:self.bounds]; _scrollView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); _scrollView.backgroundColor = [UIColor clearColor]; @@ -158,7 +161,7 @@ - (void)setFadeLength:(CGFloat)fadeLength } } -- (SimpleAttributedLabel *)mainLabel +- (UILabel *)mainLabel { return [self.labels objectAtIndex:0]; } @@ -238,6 +241,14 @@ - (void)setScrollSpeed:(float)speed - (void)setScrollDirection:(CBAutoScrollDirection)direction { + if (APP_IS_RTL) { + if (direction == CBAutoScrollDirectionRight) { + direction = CBAutoScrollDirectionLeft; + } else { + direction = CBAutoScrollDirectionRight; + } + } + _scrollDirection = direction; [self scrollLabelIfNeeded]; @@ -279,8 +290,8 @@ - (void)scrollLabelIfNeeded [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(scrollLabelIfNeeded) object:nil]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(enableShadow) object:nil]; - BOOL doScrollLeft = (self.scrollDirection == CBAutoScrollDirectionLeft); - self.scrollView.contentOffset = (doScrollLeft ? CGPointZero : CGPointMake(labelWidth + _labelSpacing, 0)); + BOOL doScrollLeft = self.scrollDirection == CBAutoScrollDirectionLeft; + self.scrollView.contentOffset = (doScrollLeft ? CGPointMake(0.0f, 0.0f) : CGPointMake(self.scrollView.contentSize.width - CGRectGetWidth(self.scrollView.frame), 0)); // Add the right shadow [self applyGradientMaskForFadeLength:self.fadeLength enableLeft:NO]; @@ -290,36 +301,71 @@ - (void)scrollLabelIfNeeded // animate the scrolling NSTimeInterval duration = labelWidth / self.scrollSpeed; - [UIView animateWithDuration:duration delay:self.pauseInterval options:self.animationOptions | UIViewAnimationOptionAllowUserInteraction animations:^{ - // adjust offset - self.scrollView.contentOffset = (doScrollLeft ? CGPointMake(labelWidth + _labelSpacing, 0) : CGPointZero); - } completion:^(BOOL finished) { +// SEL selector = @selector(_setContentOffsetAnimationDuration:); +// NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self.scrollView methodSignatureForSelector:selector]]; +// +// [invocation setSelector:selector]; +// [invocation setTarget:self.scrollView]; +// [invocation setArgument:&duration atIndex:2]; +// [invocation invoke]; + + +// [self.scrollView setContentOffset:(doScrollLeft ? CGPointMake(labelWidth + _labelSpacing, 0) : CGPointZero) animated:YES]; +// + + if (_timer1) { + dispatch_source_cancel(_timer1); + _timer1 = nil; + } + + dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, self.pauseInterval * NSEC_PER_SEC); + dispatch_time_t pauseTime = startTime; + + _timer1 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); + + dispatch_source_set_timer(_timer1, startTime, pauseTime, 0.0f * NSEC_PER_SEC); + dispatch_source_set_event_handler(_timer1, ^{ + [self.scrollView setContentOffset:(doScrollLeft ? CGPointMake(labelWidth + _labelSpacing, 0) : CGPointMake(labelWidth - CGRectGetWidth(self.scrollView.frame), 0)) withTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn] duration:duration]; + }); + dispatch_resume(_timer1); + + if (_timer2) { + dispatch_source_cancel(_timer2); + _timer2 = nil; + } + + _timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); + + startTime = dispatch_time(DISPATCH_TIME_NOW, (self.pauseInterval + duration) * NSEC_PER_SEC); + pauseTime = startTime; + + dispatch_source_set_timer(_timer2, startTime, pauseTime, 0.0f * NSEC_PER_SEC); + dispatch_source_set_event_handler(_timer2, ^{ _isScrolling = NO; // remove the left shadow [self applyGradientMaskForFadeLength:self.fadeLength enableLeft:NO]; // setup pause delay/loop - if (finished) - { - [self performSelector:@selector(scrollLabelIfNeeded) withObject:nil]; - } - }]; + [self performSelector:@selector(scrollLabelIfNeeded) withObject:nil afterDelay:0.1f]; + }); + dispatch_resume(_timer2); } - (void)refreshLabels { - __block float offset = 0.0; - + if (!self.text) return; + // calculate the label size - CGSize labelSize = [self.mainLabel.text sizeWithFont:self.mainLabel.font - constrainedToSize:CGSizeMake(CGFLOAT_MAX, CGRectGetHeight(self.bounds))]; + CGSize labelSize = [self.mainLabel.text sizeWithAttributes:@{NSFontAttributeName: self.mainLabel.font}]; + + __block float offset = 0.0f; - each_object(self.labels, ^(SimpleAttributedLabel *label) { + each_object(self.labels, ^(UILabel *label) { CGRect frame = label.frame; - frame.origin.x = offset; - frame.size.height = CGRectGetHeight(self.bounds); frame.size.width = labelSize.width + 2 /*Magic number*/; + frame.origin.x = APP_IS_RTL ? (CGRectGetWidth(frame) + _labelSpacing) * (self.labels.count - 1) - offset : offset; + frame.size.height = CGRectGetHeight(self.bounds); label.frame = frame; @@ -329,20 +375,33 @@ - (void)refreshLabels offset += CGRectGetWidth(label.bounds) + _labelSpacing; }); - self.scrollView.contentOffset = CGPointZero; + [(MOScrollView *)self.scrollView performSelector:@selector(stopAnimation) withObject:nil]; + self.scrollView.contentOffset = CGPointZero; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(scrollLabelIfNeeded) object:nil]; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(enableShadow) object:nil]; + + if (_timer1) { + dispatch_source_cancel(_timer1); + _timer1 = nil; + } + if (_timer2) { + dispatch_source_cancel(_timer2); + _timer2 = nil; + } + // if the label is bigger than the space allocated, then it should scroll if (CGRectGetWidth(self.mainLabel.bounds) > CGRectGetWidth(self.bounds) ) { CGSize size; - size.width = CGRectGetWidth(self.mainLabel.bounds) + CGRectGetWidth(self.bounds) + _labelSpacing; + size.width = CGRectGetWidth(self.mainLabel.bounds) * 2.0f + _labelSpacing; size.height = CGRectGetHeight(self.bounds); self.scrollView.contentSize = size; EACH_LABEL(hidden, NO) [self applyGradientMaskForFadeLength:self.fadeLength enableLeft:_isScrolling]; - + [self scrollLabelIfNeeded]; } else @@ -354,7 +413,7 @@ - (void)refreshLabels self.scrollView.contentSize = self.bounds.size; self.mainLabel.frame = self.bounds; self.mainLabel.hidden = NO; - //self.mainLabel.textAlignment = self.textAlignment; + self.mainLabel.textAlignment = self.textAlignment; [self applyGradientMaskForFadeLength:0 enableLeft:NO]; }