给代码绘制计时器数字加个效果

2,755 阅读3分钟

废话开篇:简单的绘制了一下计时器的数字展示效果,这里再封装一些效果,在变化的同时让其看上去更饱满些

绘制数字: # 代码绘制计时器数字

一、先看效果

1、动画效果

屏幕录制2022-11-08 下午1.05.52.gif

2、淡出效果

屏幕录制2022-11-08 下午1.09.09.gif

3、无效果

屏幕录制2022-11-08 下午1.12.43.gif

除了一些效果外,还封装了数字的对齐方式

1、左对齐

image.png

2、中间

image.png

3、右对齐

image.png

二、代码

1、ReadSecondsView 类,完善数字变化效果

ReadSecondsView.h

#import <UIKit/UIKit.h>
#import "NumberView.h"

@interface ReadSecondsView : UIView
@property(nonatomic,assign) NSInteger currentNum;

- (instancetype)initWithFrame:(CGRect)frame numberColor:(UIColor *)numberColor numberChangeAnimation:(NumberChangeAnimation)numberChangeAnimation;

@end

ReadSecondsView.m


#import "ReadSecondsView.h"

#import "NumberSectionView.h"

@interface ReadSecondsView()

//展示的view视图与数字应对dic
@property(nonatomic,strong) NSDictionary * mapNumShowDic;
//数字颜色
@property (nonatomic,strong) UIColor * numberColor;
//动画
@property (nonatomic,assign) NumberChangeAnimation numberChangeAnimation;
@end
  
@implementation ReadSecondsView

- (instancetype)initWithFrame:(CGRect)frame numberColor:(UIColor *)numberColor numberChangeAnimation:(NumberChangeAnimation)numberChangeAnimation
{
    if (self = [super initWithFrame:frame]) {
        self.numberChangeAnimation = numberChangeAnimation;
        self.numberColor = numberColor;
        [self createNumberSection];
    }
    return self;
}

#pragma mark - 配置数字展示项(判断数字对应的展示哪些节段)
- (NSDictionary *)mapNumShowDic
{
    if(_mapNumShowDic == nil){
        _mapNumShowDic = @{
            @(0):@[@(0),@(2),@(3),@(4),@(5),@(6)],
            @(1):@[@(5),@(6)],
            @(2):@[@(0),@(1),@(2),@(4),@(5)],
            @(3):@[@(0),@(1),@(2),@(5),@(6)],
            @(4):@[@(1),@(3),@(5),@(6)],
            @(5):@[@(0),@(1),@(2),@(3),@(6)],
            @(6):@[@(0),@(1),@(2),@(3),@(4),@(6)],
            @(7):@[@(0),@(5),@(6)],
            @(8):@[@(0),@(1),@(2),@(3),@(4),@(5),@(6)],
            @(9):@[@(0),@(1),@(2),@(3),@(5),@(6)],
        };
    }
    return _mapNumShowDic;
}

  
#pragma mark - 设置当前数字
- (void)setCurrentNum:(NSInteger)currentNum
{
    _currentNum = currentNum % 10;
    //变换数字
    [self changeNumberUI];
}

//变换数字(设置不通的变换方式)
- (void)changeNumberUI
{
    NSArray * showNumSectionArr = self.mapNumShowDic[@(_currentNum)];
    for (UIView * subView in [self subviews]) {
        if([subView isKindOfClass:[NumberSectionView class]]){
            NumberSectionView * numberSectionViewSubView = (NumberSectionView *)subView;
            switch (self.numberChangeAnimation) {
                case NumberChangeAnimationNone:
                {
                    //默认
                    numberSectionViewSubView.hidden = ![showNumSectionArr containsObject:@(numberSectionViewSubView.index)];
                }
                    break;
                case NumberChangeAnimationTurn: {
                    //翻页
                    if (![showNumSectionArr containsObject:@(numberSectionViewSubView.index)]) {
                        if (numberSectionViewSubView.isValuable) {
                            [UIView animateWithDuration:0.5 animations:^{
                                numberSectionViewSubView.layer.transform = CATransform3DRotate(numberSectionViewSubView.layer.transform, M_PI_2, 1, 0, 0);
                            } completion:^(BOOL finished) {
                                numberSectionViewSubView.isValuable = NO;
                            }];
                        }
                    } else {
                        if (!numberSectionViewSubView.isValuable) {
                            [UIView animateWithDuration:0.5 animations:^{
                                numberSectionViewSubView.layer.transform = CATransform3DRotate(numberSectionViewSubView.layer.transform, - M_PI_2, 1, 0, 0);
                            } completion:^(BOOL finished) {
                                numberSectionViewSubView.isValuable = YES;
                            }];
                        }
                    }
                }
                    break;
                case NumberChangeAnimationFade: {
                    //淡出
                    [UIView animateWithDuration:0.3 animations:^{
                        numberSectionViewSubView.alpha = [showNumSectionArr containsObject:@(numberSectionViewSubView.index)] ? 1 : 0;
                    } completion:^(BOOL finished) {
                        if (finished) {
                            numberSectionViewSubView.hidden = ![showNumSectionArr containsObject:@(numberSectionViewSubView.index)];
                        }
                    }];
                }
                    break;
                default:
                    break;
            }
        }
    }
}

#pragma mark - 创建数字节段
- (void)createNumberSection{
    //创建7个节段
    for (int i = 0; i < 7; i ++) {
        NumberSectionView * numberSectionView = [[NumberSectionView alloc] initWithFrame:CGRectMake(0, self.frame.size.height / 2.0, self.frame.size.width, self.frame.size.height) withIndex:i numberColor:self.numberColor];
        numberSectionView.layer.anchorPoint = CGPointMake(0.5, 1);
        [self addSubview:numberSectionView];
    }
}

@end

ReadSecondsView 类的只能展示一个数字(0-9),需要一组 ReadSecondsView 来展示各个位的数字

2、NumberView 来展示一串数字

NumberView.h

//数字对其位置
typedef NS_ENUM(NSInteger,NumberAlignmentType) {
    NumberAlignmentLeft,
    NumberAlignmentCenter,
    NumberAlignmentRight
};

//动画
typedef NS_ENUM(NSInteger,NumberChangeAnimation) {
    NumberChangeAnimationNone,//无动画
    NumberChangeAnimationTurn,//翻页
    NumberChangeAnimationFade //淡出
};

@interface NumberView : UIView

//当前数字
@property (nonatomic,assign) NSInteger currentNum;
//数字对齐方式
@property (nonatomic,assign) NumberAlignmentType numberAlignmentType;
//最大位数
@property (nonatomic,assign) NSInteger maxDigits;
//动画
@property (nonatomic,assign) NumberChangeAnimation numberChangeAnimation;

- (instancetype)initWithFrame:(CGRect)frame maxDigits:(NSInteger)maxDigits numberAlignmentType:(NumberAlignmentType)numberAlignmentType numberColor:(UIColor *)numberColor numberChangeAnimation:(NumberChangeAnimation)numberChangeAnimation;

@end

NumberView.m

#import "NumberView.h"
#import "ReadSecondsView.h"

@interface NumberView()

//单独数字的size
@property(nonatomic,assign) CGSize separateNumnerViewSize;
//单独数字的y
@property(nonatomic,assign) float separateNumnerViewY;
//定时器
@property(nonatomic,strong) NSTimer * timer;
//保存全部数字view
@property(nonatomic,strong) NSMutableArray * readSecondsViewArr;
//主体view
@property(nonatomic,strong) UIView * contentView;
//数字颜色
@property (nonatomic,strong) UIColor * numberColor;

@end

@implementation NumberView

- (instancetype)initWithFrame:(CGRect)frame maxDigits:(NSInteger)maxDigits numberAlignmentType:(NumberAlignmentType)numberAlignmentType numberColor:(UIColor *)numberColor numberChangeAnimation:(NumberChangeAnimation)numberChangeAnimation
{
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor whiteColor];
        self.numberColor = numberColor;
        self.numberChangeAnimation = numberChangeAnimation;
        [self initDefaultDataWithMaxDigits:maxDigits numberAlignmentType:numberAlignmentType];
        [self createContentView];
        [self startTimer];
    }
    return self;
}

//设置默认数据
- (void)initDefaultDataWithMaxDigits:(NSInteger)maxDigits numberAlignmentType:(NumberAlignmentType)numberAlignmentType
{
    //对齐方式
    self.numberAlignmentType = numberAlignmentType;
    //最大位数
    self.maxDigits = maxDigits;
    //计算单独数字的size
    float width = self.frame.size.width / self.maxDigits;
    float height = width * 2;
    if(height > self.frame.size.height){
        height = self.frame.size.height;
        width = height / 2.0;
    }
    self.separateNumnerViewSize = CGSizeMake(width, height);
    //计算单独数字的y
    self.separateNumnerViewY = (self.frame.size.height - height) / 2.0;
}

//设置默认第一位
- (void)createContentView
{
    float x = 0;
    switch (self.numberAlignmentType) {
        case NumberAlignmentLeft:
        {
            x = 0;
        }
            break;
        case NumberAlignmentCenter:
        {
            x = (self.frame.size.width) / 2.0;
        }
            break;
        case NumberAlignmentRight:
        {
            x = (self.frame.size.width);
        }
            break;
        default:
            break;
    }
    self.contentView = [[UIView alloc] initWithFrame:CGRectMake(x, 0, 0, self.frame.size.height)];
    [self addSubview:self.contentView];
}

- (NSMutableArray *)readSecondsViewArr
{
    if (!_readSecondsViewArr) {
        _readSecondsViewArr = @[].mutableCopy;
    }
    return _readSecondsViewArr;
}

#pragma mark - 设置当前数字
- (void)setCurrentNum:(NSInteger)currentNum
{
    _currentNum = currentNum;
    [self parsingCurrentNum];
}

#pragma mark - 解析数字
- (void)parsingCurrentNum
{
    NSInteger tempCurrent = _currentNum;
    NSMutableArray * saveAllPositionNumArr = @[].mutableCopy;
    while (tempCurrent > 0) {
        [saveAllPositionNumArr addObject:@(tempCurrent % 10)];
        tempCurrent /= 10;
    }
    saveAllPositionNumArr = (NSMutableArray *)[[saveAllPositionNumArr reverseObjectEnumerator] allObjects];
    [self setNumUIWithAllPositionNums:saveAllPositionNumArr];
}

#pragma mark - 创建并赋值数字
- (void)setNumUIWithAllPositionNums:(NSArray *)saveAllPositionNumArr
{
    for (int i = 0; i < saveAllPositionNumArr.count; i++) {
        NSInteger number = [saveAllPositionNumArr[i] integerValue];
        if(self.readSecondsViewArr.count == 0 || i > self.readSecondsViewArr.count - 1){
            ReadSecondsView * readSecondsView = [[ReadSecondsView alloc] initWithFrame:CGRectMake(self.separateNumnerViewSize.width * i, self.separateNumnerViewY, self.separateNumnerViewSize.width, self.separateNumnerViewSize.height) numberColor:self.numberColor numberChangeAnimation:self.numberChangeAnimation];
            readSecondsView.currentNum = number;
            [self.readSecondsViewArr addObject:readSecondsView];
            [self.contentView addSubview:readSecondsView];
        } else {
            ReadSecondsView * readSecondsView = self.readSecondsViewArr[i];
            readSecondsView.currentNum = number;
        }
    }
    //根据对齐方式设置contentView的frame
    CGRect contentfFrame;
    float contentWidth = saveAllPositionNumArr.count * self.separateNumnerViewSize.width;
    switch (self.numberAlignmentType) {
        case NumberAlignmentLeft:
        {
            contentfFrame = CGRectMake(0, 0, contentWidth, self.separateNumnerViewSize.height);
        }
            break;
        case NumberAlignmentCenter:
        {
            contentfFrame = CGRectMake((self.frame.size.width - contentWidth) / 2.0, 0, contentWidth, self.separateNumnerViewSize.height);
        }
            break;
        case NumberAlignmentRight:
        {
            contentfFrame = CGRectMake(self.frame.size.width - contentWidth, 0, contentWidth, self.separateNumnerViewSize.height);
        }
            break;
        default:
            break;
    }
    self.contentView.frame = contentfFrame;
}

#pragma mark - 开启定时器
- (void)startTimer
{
    __weak typeof(self) weakSelf = self;
    if ( @available(iOS 10.0, *)) {
        weakSelf.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
            weakSelf.currentNum ++;
        }];
        [weakSelf.timer fire];
    }
}

- (void)dealloc
{
    [self.timer invalidate];
    self.timer = nil;
}
3、创建与使用
NumberView * numberView = [[NumberView alloc] initWithFrame:CGRectMake(20, 0, self.view.frame.size.width - 40, 60) maxDigits:10 numberAlignmentType:(NumberAlignmentRight) numberColor:[UIColor redColor] numberChangeAnimation:(NumberChangeAnimationNone)];
numberView.center = self.view.center;
[self.view addSubview:numberView];

三、总结与思考

到这里在原来的基础上就添加了一些数字变换的效果,代码拙劣,大神勿笑。[抱拳][抱拳][抱拳]