• 文字动画效果


    新建俩个类:

    DNOLabelAnimation : UILabel

    DNOSingleText : NSObject

    DNOLabelAnimation.h

    #import <UIKit/UIKit.h>
    
    typedef enum {
        DNOLabelAnimationTypeNormal = 0,
        DNOLabelAnimationTypeWave   = 1
    }DNOLabelAnimationType;
    
    @interface DNOLabelAnimation : UILabel
    @property (nonatomic, copy) NSString           *text;
    @property (nonatomic, copy) NSAttributedString *attributedText;
    
    @property (nonatomic, assign) DNOLabelAnimationType type;
    
    @property (nonatomic, assign) CGFloat    animationHeight;
    @property (nonatomic, assign) NSUInteger rate; // 1 is fastest 10 is slowest, default is 2
    @property (nonatomic, assign) CGFloat    kerning;
    
    - (instancetype)initWithFrame:(CGRect)frame text:(NSString *)text;
    - (instancetype)initWithFrame:(CGRect)frame attributedText:(NSAttributedString *)attributedText;
    
    - (void)startAnimation;
    - (void)pauseAnimation;
    - (void)stopAnimation;
    
    @end

    DNOLabelAnimation.m

    #import "DNOLabelAnimation.h"
    #import "DNOSingleText.h"
    
    //static int loopCount_ = -1;
    
    @interface DNOLabelAnimation ()
    
    @property (nonatomic, strong) NSMutableArray <DNOSingleText *>*allText;
    @property (nonatomic, strong) CADisplayLink *time;
    @property (nonatomic, assign) int loopCount;
    
    @property (nonatomic, assign) int steps;
    
    @end
    
    @implementation DNOLabelAnimation
    
    @synthesize text = _text;
    @synthesize attributedText = _attributedText;
    
    - (instancetype)initWithCoder:(NSCoder *)coder
    {
        self = [super initWithCoder:coder];
        if (self) {
            [self prepare];
            [self setNeedsDisplay];
        }
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame attributedText:(NSAttributedString *)attributedText
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self prepare];
            self.attributedText = attributedText;
        }
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame text:(NSString *)text
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self prepare];
            self.text = text;
        }
        return self;
    }
    
    - (void)prepare
    {
        self.loopCount = -1;
    }
    
    - (void)sizeToFit
    {
        [self setFrame:({
            CGFloat x = self.frame.origin.x;
            CGFloat y = self.frame.origin.y;
            CGFloat width = self.kerning * self.allText.count;
            CGFloat height = self.font.ascender - self.font.descender + self.animationHeight;
            CGRectMake(x, y, width, height);
        })];
    }
    - (void)start
    {
        self.steps = 0;
        self.steps ++;
        if (self.steps % 3 == 0 || self.steps % 3 == 1 ) {
            [self setNeedsDisplay];
        }
        if (self.steps > 1000) {
            self.steps = 0;
        }
    }
    
    
    - (void)startAnimation
    {
        [self.time invalidate];
        self.time = [CADisplayLink displayLinkWithTarget:self selector:@selector(start)];
        [self.time addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    }
    
    - (void)pauseAnimation
    {
        [self.time invalidate];
        self.time = nil;
    }
    
    - (void)stopAnimation
    {
        [self.time invalidate];
        self.time = nil;
        self.loopCount = -1;
        [self.allText makeObjectsPerformSelector:@selector(normalReset)];
        [self.allText makeObjectsPerformSelector:@selector(waveReset)];
        [self setNeedsDisplay];
    }
    
    
    - (void)drawRect:(CGRect)rect {
        __block CGFloat x = 0;
        __weak typeof(self) weakSelf = self;
        [self.allText enumerateObjectsUsingBlock:^(DNOSingleText *singleText, NSUInteger idx, BOOL *stop) {
            CGFloat location = 0;
            
            // 仅仅在能第一次遍历玩所有的文字的时候调用
            if (self.loopCount == idx * weakSelf.rate) {
                location = [singleText locationWithFirstEnumerate];
            }else{
                // 让其他的文字在一开始的时候不要动
                location = 0;
            }
            // 已经被遍历过的标志
            if (singleText.enumerated) {
                // 判断动画模式
                if (weakSelf.type) {
                    location = [singleText locationWithWaveAnimationCompletion:^{
                        if (idx == weakSelf.allText.count - 1) {
                            [weakSelf.allText makeObjectsPerformSelector:@selector(waveReset)];
                            self.loopCount = -1;
                        }
                    }];
                } else {
                    location = [singleText locationWithNormalAnimation];
                }
            }
            CGFloat trueLocation = weakSelf.animationHeight - location;
    
            CGRect trueRect = CGRectMake(x, trueLocation, weakSelf.textSize, weakSelf.textSize);
            NSMutableDictionary *attibutes = [NSMutableDictionary dictionary];
            attibutes[NSFontAttributeName] = weakSelf.font;
            attibutes[NSForegroundColorAttributeName] = singleText.textColor;
            [singleText.text drawInRect:trueRect withAttributes:attibutes];
            x += weakSelf.kerning;
        }];
        self.loopCount ++;
    
    }
    
    #pragma mark -
    #pragma mark setter && getter
    
    - (CGFloat)textSize
    {
        return self.font.pointSize + self.animationHeight;
    }
    
    - (void)setText:(NSString *)text
    {
        _text = text;
        
        [self.allText removeAllObjects];
        for (int i = 0; i < text.length; ++i) {
            
            DNOSingleText *singleText = [DNOSingleText singleTextWithAnimationRange: text.length];
            singleText.text = [text substringWithRange:NSMakeRange(i, 1)];
            [self.allText addObject:singleText];
        }
        [self sizeToFit];
        [self setNeedsDisplay];
    }
    
    - (void)setAttributedText:(NSAttributedString *)attributedText
    {
        [super setAttributedText:attributedText];
        [self.allText removeAllObjects];
        for (int i = 0; i < attributedText.length; ++i) {
            
            DNOSingleText *singleText = [DNOSingleText singleTextWithAnimationRange: attributedText.length];
            singleText.text = [attributedText.string substringWithRange:NSMakeRange(i, 1)];
            NSDictionary *attributed = [attributedText attributesAtIndex:i effectiveRange:nil];
            singleText.textColor = attributed[NSForegroundColorAttributeName];
            [self.allText addObject:singleText];
        }
        [self sizeToFit];
        [self setNeedsDisplay];
    }
    
    - (void)setType:(DNOLabelAnimationType)type
    {
        _type = type;
        self.loopCount = -1;
        [self.allText makeObjectsPerformSelector:@selector(normalReset)];
        [self.allText makeObjectsPerformSelector:@selector(waveReset)];
    }
    
    - (CGFloat)kerning
    {
        return _kerning + self.font.pointSize;
    }
    
    
    - (NSUInteger)rate
    {
        if (!_rate) {
            _rate = 2;
        }
        if (_rate < 1) {
            _rate = 1;
        }
        if (_rate > 10) {
            _rate = 10;
        }
        return _rate;
    }
    
    //- (UIFont *)font
    //{
    //    if (![super font]) {
    //        return [UIFont systemFontOfSize:15];
    //    }
    //    return [super font];
    //}
    
    @synthesize animationHeight = _animationHeight;
    
    - (void)setAnimationHeight:(CGFloat)animationHeight
    {
        _animationHeight = animationHeight + self.font.pointSize;
    }
    
    - (CGFloat)animationHeight
    {
        if (!_animationHeight) {
            _animationHeight = self.font.pointSize;
        }
        return _animationHeight;
    }
    
    - (NSMutableArray<DNOSingleText *> *)allText
    {
        if (!_allText) {
            _allText = [@[] mutableCopy];
        }
        return _allText;
    }
    
    @end

    DNOSingleText.h

    #import <UIKit/UIKit.h>
    
    @interface DNOSingleText : NSObject
    
    @property (nonatomic, copy  ) NSString *text;
    @property (nonatomic, strong) UIColor  *textColor;
    @property (nonatomic, assign) CGFloat  animationRange;
    @property (nonatomic, assign) BOOL     enumerated;
    
    + (instancetype)singleTextWithAnimationRange:(CGFloat)animationRange;
    
    - (CGFloat)locationWithFirstEnumerate;
    
    - (CGFloat)locationWithNormalAnimation;
    - (void)normalReset;
    
    - (CGFloat)locationWithWaveAnimationCompletion:(void(^)())completion;
    - (void)waveReset;
    
    @end

    DNOSingleText.m

    #import "DNOSingleText.h"
    #define myRandomColor [UIColor colorWithRed:arc4random()%256/255.0 green:arc4random()%256/255.0 blue:arc4random()%256/255.0 alpha:1]
    
    @interface DNOSingleText ()
    {
        CGFloat _normalSteps;
        CGFloat _waveSteps;
        BOOL    _directionChange;
    }
    
    @end
    
    @implementation DNOSingleText
    
    + (instancetype)singleTextWithAnimationRange:(CGFloat)animationRange
    {
        DNOSingleText *obj = [[self alloc] init];
        obj.animationRange = animationRange;
        return obj;
    }
    
    - (void)calculateStep
    {
        _directionChange ? _normalSteps-- : _normalSteps++;
        
        if (_normalSteps > self.animationRange) {
            _directionChange = YES;
        } else if (_normalSteps < 0) {
            _directionChange = NO;
        }
    }
    
    - (CGFloat)locationWithNormalAnimation
    {
        [self calculateStep];
        return _normalSteps;
    }
    
    - (CGFloat)locationWithFirstEnumerate
    {
        [self calculateStep];
        _normalSteps += 1;
        if (_normalSteps > self.animationRange) {
            _normalSteps = self.animationRange - (_normalSteps - self.animationRange);
        }
        self.enumerated = YES;
        return _normalSteps;
    }
    
    - (CGFloat)locationWithWaveAnimationCompletion:(void (^)())completion
    {
        _waveSteps++;
        if (_waveSteps > 2 * self.animationRange) {
            completion();
            return 0;
        }
        return [self locationWithNormalAnimation];
    }
    
    - (void)normalReset
    {
        self.enumerated  = NO;
        _directionChange = NO;
        _normalSteps     = 0;
    }
    
    - (void)waveReset
    {
        _waveSteps = 0;
        [self normalReset];
    }
    
    
    @end

    然后在需要的地方调用

    #import "ViewController.h"
    #import "DNOLabelAnimation.h"
    
    #define myRandomColor [UIColor colorWithRed:arc4random()%256/255.0 green:arc4random()%256/255.0 blue:arc4random()%256/255.0 alpha:1]
    #define myWidth  [UIScreen mainScreen].bounds.size.width
    #define myHeight [UIScreen mainScreen].bounds.size.height
    
    @interface ViewController ()
    @property (nonatomic, strong) NSMutableArray *textViews;
    @property (nonatomic, assign) DNOLabelAnimationType type;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        [self demo1];
        [self demo2];
        [self demo3];
        [self demo4];
        [self demo5];
    }
    - (void)demo1{
        
        NSDictionary *attribute = @{NSForegroundColorAttributeName : myRandomColor};
        NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"一一一一一一一一一一一一一" attributes:attribute];
        
        [string addAttribute:NSForegroundColorAttributeName value:myRandomColor range:NSMakeRange(2, 2)];
        [string addAttribute:NSForegroundColorAttributeName value:myRandomColor range:NSMakeRange(4, 2)];
        [string addAttribute:NSForegroundColorAttributeName value:myRandomColor range:NSMakeRange(6, 2)];
        [string addAttribute:NSForegroundColorAttributeName value:myRandomColor range:NSMakeRange(8, 2)];
        
        DNOLabelAnimation *textView = [[DNOLabelAnimation alloc] initWithFrame:CGRectMake(20, 60, 0, 0) attributedText:string];
        
        [textView sizeToFit];
        [self.view addSubview:textView];
        [self.textViews addObject:textView];
        [self getButtonWithPoint:CGPointMake(myWidth - 60, 60) tag:1];
        
        
        
        
    }
    - (void)getButtonWithPoint:(CGPoint)point tag:(NSInteger)tag
    {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
        button.frame = CGRectMake(point.x, point.y, 60, 30);
        [button addTarget:self action:@selector(buttonDidClick:) forControlEvents:UIControlEventTouchUpInside];
        [button setTitle:@"start" forState:UIControlStateNormal];
        [button setTitle:@"pause" forState:UIControlStateSelected];
        [self.view addSubview:button];
        button.tag = tag;
    }
    
    - (void)buttonDidClick:(UIButton *)sender
    {
        sender.selected = !sender.selected;
        if (sender.selected) {
            [self.textViews[sender.tag - 1] startAnimation];
        }else{
            [self.textViews[sender.tag - 1] stopAnimation];
            //[self.textViews[sender.tag - 1] pauseAnimation];
        }
    }
    - (NSMutableArray *)textViews
    {
        if (!_textViews) {
            _textViews = [[NSMutableArray alloc] init];
        }
        return _textViews;
    }
    
    - (void)demo2 {
        NSDictionary *attribute = @{NSForegroundColorAttributeName : myRandomColor};
        NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"ABCDEFGHIJ" attributes:attribute];
        
        DNOLabelAnimation *textView = [[DNOLabelAnimation alloc] initWithFrame:CGRectMake(20, 120, 0, 0) attributedText:string];
        
        textView.type = self.type;
        textView.font = [UIFont systemFontOfSize:30];
        [textView sizeToFit];
        
        [self.view addSubview:textView];
        [self.textViews addObject:textView];
        
        [self getButtonWithPoint:CGPointMake(myWidth - 60, 120) tag:2];
    }
    
    - (void)demo3 {
        NSDictionary *attribute = @{NSForegroundColorAttributeName : myRandomColor};
        NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"abcdefghij" attributes:attribute];
        DNOLabelAnimation *textView = [[DNOLabelAnimation alloc] initWithFrame:CGRectMake(20, 180, 0, 0) attributedText:string];
        
        textView.type = self.type;
        textView.font = [UIFont fontWithName:@"Courier" size:30];
        textView.rate = 1;
        [textView sizeToFit];
        [self.view addSubview:textView];
        [self.textViews addObject:textView];
        
        [self getButtonWithPoint:CGPointMake(myWidth - 60, 180) tag:3];
    }
    
    - (void)demo4 {
        
        DNOLabelAnimation *textView = [[DNOLabelAnimation alloc] initWithFrame:CGRectMake(20, 240, 0, 0) text:@"黑化肥会挥发"];
        
        textView.type = self.type;
        textView.font = [UIFont fontWithName:@"Courier" size:30];
        textView.rate = 10;
        [textView sizeToFit];
        [self.view addSubview:textView];
        [self.textViews addObject:textView];
        
        [self getButtonWithPoint:CGPointMake(myWidth - 60, 240) tag:4];
    }
    
    - (void)demo5 {
        
        DNOLabelAnimation *textView = [[DNOLabelAnimation alloc] initWithFrame:CGRectMake(20, 300, 0, 0) text:@"做人呢,最重要的就是不能让别人开心."];
        
        textView.type = self.type;
        textView.font = [UIFont systemFontOfSize:10];
        textView.kerning = 4;
        [textView sizeToFit];
        [self.view addSubview:textView];
        [self.textViews addObject:textView];
        
        [self getButtonWithPoint:CGPointMake(myWidth - 60, 300) tag:5];
    }
  • 相关阅读:
    Sql 复习(1)
    记录一次git issue
    JWT自校验框架
    分布式事务分布式锁的常用解决方式
    SpringBoot开发文档
    SpringCloud的使用以及五大核心组件
    SpringMVC
    关于开发中使用AOP的坑
    SpringCloud使用feign远程调用服务注入映射接口失败问题
    springBoot使用Restful跳转路径回显异常问题
  • 原文地址:https://www.cnblogs.com/LzwBlog/p/5814844.html
Copyright © 2020-2023  润新知