在上一篇文章 从0开始自定义一个支付密码输入框(1) 中,已经实现了密码框的基本功能,本篇要给圆点加上出现和消失的动画。
知识储备
动画效果:CADisplayLink
实现效果
实现过程
1.初始化CADisplayLink
-(CADisplayLink *)displayLink{
if (_displaylink == nil) {
_displaylink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateString)];
_displaylink.paused = YES;
[_displaylink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
return _displaylink;
}
2.动画中,我们实际上是通过改变圆点绘制时的颜色透明度(0~1)和大小倍数(0~1)实现效果。所以我们需要两个可变数组来保存每个圆点的透明度和半径
NSMutableArray <NSNumber *>* dotAlphas;
NSMutableArray <NSNumber *>* dotScans;
-(NSMutableArray *)dotAlphas{
if (dotAlphas == nil) {
dotAlphas = [NSMutableArray arrayWithCapacity:self.boxCount];
for (int i = 0; i < self.boxCount; i ++) {
dotAlphas[i] = @0;
}
}
return dotAlphas;
}
-(NSMutableArray *)dotScans{
if (dotScans == nil) {
dotScans = [NSMutableArray arrayWithCapacity:self.boxCount];
for (int i = 0; i < self.boxCount; i ++) {
dotScans[i] = @0;
}
}
return dotScans;
}
3.改变圆点的绘制方法,让它根据数组中的值来绘制
/**
* 绘制圆点
* context 上下文
* size 总大小(self的size)
**/
-(void)drawDot:(CGContextRef)context
size:(CGSize)size{
//圆心的y坐标
float cy = size.height / 2;
//半径
float half = size.width / self.boxCount / 2;
for (int i = 0; i < self.boxCount; i ++) {
//设置填充颜色
CGContextSetFillColorWithColor(context, [self.dotColor colorWithAlphaComponent:[self.dotAlphas[i] floatValue]].CGColor);
//圆心的x坐标
float cx = size.width * i / self.boxCount + half;
//添加一个圆
CGContextAddArc(context, cx, cy, self.dotRadius * [self.dotScans[i] floatValue], 0, 2 * M_PI, 0);
//绘制填充
CGContextDrawPath(context, kCGPathFill);
}
}
4.动画
由于CADisplayLink启动后会一直调用方法,所以需要定义开始时间、动画时长、结束时间来控制动画的开始和结束。
@property (assign, nonatomic) CFTimeInterval showDuration; //圆点的动画时间,默认为0.2s
@property (assign, nonatomic) CFTimeInterval beginTime;
@property (assign, nonatomic) CFTimeInterval endTime;
//开始动画
-(void)startTextChangeAnimation{
self.beginTime = CACurrentMediaTime();
self.endTime = self.beginTime + self.showDuration;
self.displayLink.paused = NO;
}
在CADisplayLink调用方法时,根据情况判断透明度和大小的变化情况,然后重新绘界面。
- (void)updateString
{
//获取当前时间
CFTimeInterval now = CACurrentMediaTime();
NSInteger index = self.text.length - 1;
for (int i = 0; i < self.boxCount; i ++) {
//原数值(由于两个值一致,所以就用一个来计算了)
CGFloat number = [self.dotAlphas[i] floatValue];
//变化率
CGFloat d = 1;
if (self.showDuration > 0) {
//计算变化率(总数值/(动画帧数 * 动画时间)),即每次刷新屏幕变化的值
d = 1/(15.0f*self.showDuration);
}
if (i > index) {
if (number > 0) {
number -= d;
}
}else{
if (number < 1) {
number += d;
}
}
self.dotAlphas[i] = @(number);
self.dotScans[i] = @(number);
}
//重绘视图
[self setNeedsDisplay];
//如果已经到了动画结束时间,就停止
if (now > self.endTime) {
self.displayLink.paused = YES;
}
}
5.更改setText:的方法,改变时启动动画
-(void)setText:(NSString *)text{
if (text.length <= self.boxCount) {
_text = text;
[self startTextChangeAnimation];
}
}
到此,动画添加完成。
下一篇,探究一下如何弹出键盘输入数字。