代码绘制计时器数字

3,136 阅读3分钟

废话开篇:简单用代码绘制一下计时器数字,代码很简单。

一、实现效果

屏幕录制2022-11-07 上午11.39.25.gif

二、实现逻辑

绘制数字 8,可涵盖全部的数字的展示情况。将里面的节段全部单一绘制,根据不同的数字进行隐藏相应的节段

image.png

其他数字再展示情况,比如 6 隐藏了 8 右侧上面的第一个“竖节段

image.png

三、代码

正面展示

image.png

侧面展示

image.png

1、ReadSecondsView 类管理全部的节段视图
#import "ReadSecondsView.h"
#import "NumberSectionView.h"

@interface ReadSecondsView()

//展示的view视图与数字应对dic
@property(nonatomic,strong) NSDictionary * mapNumShowDic;
@property(nonatomic,assign) NSInteger currentNum;
@end

@implementation ReadSecondsView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self createNumberSection];
        [self startTimer];
    }
    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;
    NSArray * showNumSectionArr = self.mapNumShowDic[@(currentNum)];
    for (UIView * subView in [self subviews]) {
        if([subView isKindOfClass:[NumberSectionView class]]){
            NumberSectionView * numberSectionViewSubView = (NumberSectionView *)subView;
            numberSectionViewSubView.hidden = ![showNumSectionArr containsObject:@(numberSectionViewSubView.index)];
        }
    }
}

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

#pragma mark - 创建数字节段
- (void)createNumberSection{
    //创建7个节段
    for (int i = 0; i < 7; i ++) {
        NumberSectionView * numberSectionView = [[NumberSectionView alloc] initWithFrame:self.bounds withIndex:i];
        [self addSubview:numberSectionView];
    }
}

@end
2、NumberSectionView 类绘制不同位置的节段
#import "NumberSectionView.h"
#import "ChamferingNumberSectionView.h"

@interface NumberSectionView()
//节段位置
@property(nonatomic,assign) NSInteger index;
//节段宽度
@property(nonatomic,assign) float sectionWidth;
@end

@implementation NumberSectionView

- (instancetype)initWithFrame:(CGRect)frame withIndex:(NSInteger)index
{
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.01];
        self.index = index;
        [self initNumberSectionData];
        [self drawNumberSection];
    }
    return self;
}

#pragma mark - 初始化节段数据
- (void)initNumberSectionData{
    self.sectionWidth = 20;
}

#pragma mark - 绘制节段
- (void)drawNumberSection
{
    CGRect numberSectionFrame = CGRectZero;
    float maxWidth = self.frame.size.width;
    float maxHeight = self.frame.size.height;
    //横节段参数
    float crossX = (self.sectionWidth / 2.0);
    float crossWidth = (maxWidth - 2 * crossX);
    //竖节段参数
    float verticalX = 0;
    float verticalWidth = **self**.sectionWidth;
    float verticalHeight = (maxHeight - **self**.sectionWidth) / 2.0;
    switch (self.index) {
        case 0:
        {
            //上横
            float x = crossX;
            float y = 0;
            float width = crossWidth;
            float height = self.sectionWidth;
            numberSectionFrame = CGRectMake(x, y, width, height);
        }
            break;
        case 1:
        {
            //中横
            float x = crossX;
            float y = verticalHeight;
            float width = crossWidth;
            float height = self.sectionWidth;
            numberSectionFrame = CGRectMake(x, y, width, height);
        }
            break;
        case 2:
        {
            //下横
            float x = crossX;
            float y = verticalHeight * 2;
            float width = crossWidth;
            float height = self.sectionWidth;
            numberSectionFrame = CGRectMake(x, y, width, height);
        }
            break;
        case 3:
        {
            //左竖一
            float x = verticalX;
            float** y = self.sectionWidth / 2.0;
            float width = verticalWidth;
            float height = verticalHeight;
            numberSectionFrame = CGRectMake(x, y, width, height);
        }
            break;
        case 4:
        {
            //左竖二
            float x = verticalX;
            float y = self.sectionWidth / 2.0 + verticalHeight;
            float width = verticalWidth;
            float height = verticalHeight;
            numberSectionFrame = CGRectMake(x, y, width, height);
        }
            break;
        case 5:
        {
            //右竖一
            float x = maxWidth - self.sectionWidth;
            float y = self.sectionWidth / 2.0;
            float width = verticalWidth;
            float height = verticalHeight;
            numberSectionFrame = CGRectMake(x, y, width, height);
        }
            break;
        case 6:
        {
            //右竖二
            float x = maxWidth - self.sectionWidth;
            float y = self.sectionWidth / 2.0 + verticalHeight;
            float width = verticalWidth;
            float height = verticalHeight;
            numberSectionFrame = CGRectMake(x, y, width, height);
        }
            break;
        default:
            break;
    }
    ChamferingPosition chamferingPosition = (self.index != 0 && self.index != 1 && self.index != 2) ? ChamferingPositionDownUp : ChamferingPositionLeftRight;
    ChamferingNumberSectionView * numSectionView = [[ChamferingNumberSectionView alloc] initWithFrame:numberSectionFrame chamferingPosition:(chamferingPosition)];
    [self addSubview:numSectionView];
}

@end
3、ChamferingNumberSectionView 类绘制带尖角的节段

//剪切位置
typedef NS_ENUM(NSInteger,ChamferingPosition) {
    ChamferingPositionDownUp,//上下
    ChamferingPositionLeftRight//左右
};

#import "ChamferingNumberSectionView.h"

@interface ChamferingNumberSectionView()

//剪切位置
@property(nonatomic,assign) ChamferingPosition chamferingPosition;

@end

@implementation ChamferingNumberSectionView

- (instancetype)initWithFrame:(CGRect)frame chamferingPosition:(ChamferingPosition)chamferingPosition{
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor clearColor];
        self.chamferingPosition = chamferingPosition;
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    UIColor *color = [UIColor redColor];
    [color set];
    UIBezierPath *path = [UIBezierPath bezierPath];
    float width = rect.size.width;
    float height = rect.size.height;
    switch (self.chamferingPosition) {
        case ChamferingPositionDownUp:
        {
            [path moveToPoint:CGPointMake(width / 2.0, 0)];
            [path addLineToPoint:CGPointMake(width, width / 2.0)];
            [path addLineToPoint:CGPointMake(width,height - width / 2.0)];
            [path addLineToPoint:CGPointMake(width / 2.0,height)];
            [path addLineToPoint:CGPointMake(0,height - width / 2.0)];
            [path addLineToPoint:CGPointMake(0,width / 2.0)];
            [path addLineToPoint:CGPointMake(width / 2.0, 0)];
            [path fill];
            //分隔线
            color = [UIColor whiteColor];
            [color set];
            path.lineWidth = 1.0;
            [path stroke];
        }
            break;
        case ChamferingPositionLeftRight:{
            [path moveToPoint:CGPointMake(0, height / 2.0)];
            [path addLineToPoint:CGPointMake(height / 2.0, 0)];
            [path addLineToPoint:CGPointMake(width - height / 2.0,0)];
            [path addLineToPoint:CGPointMake(width,height / 2.0)];
            [path addLineToPoint:CGPointMake(width - height / 2.0,height)];
            [path addLineToPoint:CGPointMake(height / 2.0,height)];
            [path addLineToPoint:CGPointMake(0, height / 2.0)];
            [path fill];
            //分隔线
            color = [UIColor whiteColor];
            [color set];
            path.lineWidth = 1.0;
            [path stroke];
        }
            break;
        default:
            break;
    }
}

@end

总结与思考

简单的计时器数字就完成了,这里每一个节段都是被绘制到一整个父视图大小的view上,之所以这样做是考虑可以封装其他的数字动态切换方式,对于不同的数字变换只关心当前自身的节段如何变换即可,比如:旋转、反转等动画。代码拙劣,大神勿笑[抱拳][抱拳][抱拳]