寫了一個簡單的字體滾動效果。html
用了一種取巧的方式,傳入兩個一摸同樣的Label(固然也能夠是別的視圖), 話很少說,代碼裏面講解。ios
SEScrollLabel.h數組
#import <UIKit/UIKit.h>ide
/*! @brief 回調代碼塊oop
*字體
* 當滾動效果持續loopsDone次以後,isFinished值會變爲YES,執行代碼塊動畫
* @param loopsDone 滾動效果執行次數atom
* @param isFinished 是否已經結束spa
*/rest
typedef void (^PMAnimationFinished)(NSUInteger loopsDone, BOOL isFinished);
enum {
PMScrollDirectionFromLeft = 0, // Animation starts from left and continues to the right side
PMScrollDirectionFromRight = 1 // Animation starts from right and continues back to the left side
}; typedef NSUInteger PMScrollDirection;
@interface SEScrollLabel : UIScrollView
/*!
*
* @param frame 滾動視圖的frame
* @param labels 存放UILabel數組,這個demo目前最多支持兩個
* @param scrollDirection 滾動方向
* @param scrollSpeed 滾動速度,單位是 CGFloat/s
* @param loops 滾動執行次數
* @param completition 執行結束調用方法
* @return 返回SEScrollLabel對象
*/
-(instancetype)initWithFrame:(CGRect) frame labels:(NSArray *)labels
direction:(PMScrollDirection) scrollDirection
speed:(CGFloat) scrollSpeed
loops:(NSUInteger) loops
completition:(PMAnimationFinished) completition;
-(void)setText:(NSString *)text;
- (void) beginAnimation;
-(void)resetAnimation;
@end
SEScrollLabel.m
#import "SEScrollLabel.h"
#define LABEL_SPACING 30 //定義了字體滾動的間隙
@interface SEScrollLabel()
@property (nonatomic, assign) BOOL needAnimating; //是否須要滾動,label長度大於scrollLabel長度,設爲YES,不然爲NO
@property (nonatomic, assign) BOOL isAnimating; //是否正在滾動
@property (nonatomic, assign) CGFloat scrollSpeed; //滾動速度
@property (nonatomic, assign) NSInteger numberOfLoops; //滾動循環次數
@property (nonatomic, assign) NSInteger runningLoops; //當前已經執行過的滾動次數
@property (nonatomic, assign) PMScrollDirection scrollDirection; //滾動方向
@property (nonatomic, strong) PMAnimationFinished finishedBlock; //回調代碼塊
@end
@implementation SEScrollLabel
-(instancetype)initWithFrame:(CGRect) frame labels:(NSArray *)labels
direction:(PMScrollDirection) scrollDirection
speed:(CGFloat) scrollSpeed
loops:(NSUInteger) loops
completition:(PMAnimationFinished) completition
{
self = [super initWithFrame:frame];
if (self != nil)
{
UILabel *label = [labels firstObject];
CGRect labelFrame = label.frame;
if (label.frame.size.width <= frame.size.width) //若是第一個label寬度小於視圖寬度,則判斷不須要滾動顯示
{
self.contentSize = CGSizeMake(labelFrame.size.width , labelFrame.size.height);
labelFrame.origin.x = frame.size.width - labelFrame.size.width;
labelFrame.origin.y = 0;
label.frame = labelFrame;
[self addSubview:label];
_needAnimating = NO;
}
else
{
self.contentSize = CGSizeMake(labelFrame.size.width *2 + LABEL_SPACING *2 , labelFrame.size.height);
labelFrame.origin.x = 0;
labelFrame.origin.y = 0;
label.frame = labelFrame;
[self addSubview:label];
if (scrollDirection == PMScrollDirectionFromRight)
{
labelFrame.origin.x += LABEL_SPACING + labelFrame.size.width;
}
else if (scrollDirection == PMScrollDirectionFromLeft)
{
labelFrame.origin.x -= LABEL_SPACING + labelFrame.size.width;
}
UILabel *sameLabel = [labels lastObject];
sameLabel.frame = labelFrame;
[self addSubview:sameLabel];
self.scrollDirection = scrollDirection;
self.scrollSpeed = scrollSpeed;
self.numberOfLoops = loops;
self.finishedBlock = completition;
self.needAnimating = YES;
}
}
return self;
}
- (void) beginAnimation
{
//所作的動畫很是簡單,就是讓scrollView的conentOffset從0開始到contentSize.width/2的距離內不斷循環,這裏須要注意contentSize是怎麼設置才能達到想要的效果
if (!self.needAnimating) return;
if (self.isAnimating) return;
[self setContentOffset:CGPointZero];
self.isAnimating = YES;
NSTimeInterval animationDuration = (self.contentSize.width/self.scrollSpeed);
[UIView animateWithDuration:animationDuration
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
CGPoint finalPoint = CGPointZero;
if (self.scrollDirection == PMScrollDirectionFromRight)
finalPoint = CGPointMake(self.contentSize.width/2, 0);
else if (self.scrollDirection == PMScrollDirectionFromLeft)
finalPoint = CGPointMake(-self.contentSize.width/2, 0);
self.contentOffset = finalPoint;
} completion:^(BOOL finished) {
if (finished) {
self.isAnimating = NO;
BOOL restartAnimation = (self.numberOfLoops == 0 || self.runningLoops <= self.numberOfLoops);
if (self.finishedBlock)
{
self.finishedBlock((self.runningLoops+1),!restartAnimation);
}
if (restartAnimation)
[self beginAnimation];
else
[self endAnimation:NO];
self.runningLoops++;
}
}];
}
-(void)resetAnimation
{
//重置循環,將計數變爲0,而後從新開始滾動
self.isAnimating = NO;
self.runningLoops = 0;
[self beginAnimation];
}
- (void) endAnimation:(BOOL) animated {
if (!self.isAnimating) return;
self.isAnimating = NO;
[self setContentOffset:CGPointZero animated:NO];
}
-(void)setText:(NSString *)text
{
//改變文字,這裏我偷了個懶,沒有從新去修改contentSize和label的frame, 因此運行效果可能有些問題,根據本身想要的效果進行修改吧
for (UIView *view in self.subviews)
{
if ([view isKindOfClass:[UILabel class]])
{
[(UILabel *)view setText:text];
}
}
}
@end
用法實例:
SEScrollLabel *scrollLabel = [[SEScrollLabel alloc] initWithFrame:CGRectMake(0, 0, 80, 30) labels:@[label, sameLabel] direction:PMScrollDirectionFromRight speed:15 loops:3 completition:^(NSUInteger loopsDone, BOOL isFinished) {
NSLog(@"已經運行了%ld次,循環%@結束", (unsigned long)loopsDone, isFinished ? @"已經": @"還沒有");
}];
[self.view addSubview:scrollLabel];
[scrollLabel beginAnimation];
附上效果圖一枚: