对于涉及到资金的app,类似支付宝支付密码(一般为6位数字)的输入框似乎已成为标配?
所以可以封装一个自定义控件来用(主要还是想练练手😂),效果如下:
1.思路分析
要实现这个效果,有几种思路:
1.先定义单个单元的自定义控件,然后根据个数创建排列。
2.使用CGContextRef直接绘制出边框与黑点。
2.需要用到的姿势
经过考虑,决定选用第二种方案,所需技能:
1.绘制:CGContextRef和UIBezierPath
2.实时预览(可选,加上这个可以在xib中实时预览):IB_DESIGNABLE
3.分析可变属性
1.用一个String保存输入的字符串
2.边框颜色、宽度、圆角弧度以及间距
3.圆点大小、颜色
综上,.h文件中公开的属性如下
@property (nonatomic,copy) IBInspectable NSString * text; //内容
@property (nonatomic,assign) IBInspectable CGFloat dotRadius; //圆点的半径大小
@property (nonatomic,copy) IBInspectable UIColor * dotColor; //圆点的颜色
@property (nonatomic,assign) IBInspectable NSInteger boxCount; //可以输入几位数
@property (nonatomic,assign) IBInspectable CGFloat boxMargin; //输入框的间距
@property (nonatomic,assign) IBInspectable CGFloat boxRadius; //输入框的圆角半径
@property (nonatomic,assign) IBInspectable CGFloat borderWidth; //输入框边框宽度
@property (nonatomic,copy) IBInspectable UIColor * borderColor; //输入框边框颜色
4.实现
1、计算每个方框的位置
/**
* 计算方框的坐标
* i 第几个方框
* rect
**/
-(CGRect)getBoxRect:(int)i
size:(CGSize)size{
//考虑到最后一个box需要顶到右侧,所以需要加上一个_boxMargin
float boxWidth = (size.width + _boxMargin)/self.boxCount - _boxMargin;
float boxHeight = size.height;
float left = (self.boxMargin + boxWidth) * i;
float top = 0;
return CGRectMake(left, top , boxWidth , boxHeight);
}
2、使用CGContextRef绘制方框
/**
* 绘制方框
* context 上下文
* rect
**/
-(void)drawBorder:(CGContextRef)context
size:(CGSize)size{
//设置线的颜色
CGContextSetStrokeColorWithColor(context, self.borderColor.CGColor);
//设置线的宽度
CGContextSetLineWidth(context, self.borderWidth);
//调整位置,因为边框如果超出rect会被截取
CGRect bounds = CGRectInset(rect, _borderWidth * 0.5, _borderWidth * 0.5);
for (int i = 0 ; i < self.boxCount; i ++) {
CGRect rect = [self getBoxRect:i size:bounds.size];
CGRect boxRect = CGRectInset(rect, _borderWidth * 0.5, _borderWidth * 0.5);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:boxRect cornerRadius:_boxRadius];
CGContextAddPath(context, bezierPath.CGPath);
}
//绘制
CGContextDrawPath(context, kCGPathStroke);
}
3、绘制圆点
/**
* 绘制圆点
* context 上下文
* size 总大小(self的size)
**/
-(void)drawDot:(CGContextRef)context
rect:(CGRect)rect{
//调整位置,因为边框如果超出rect会被截取
CGRect bounds = CGRectInset(rect, _borderWidth * 0.5, _borderWidth * 0.5);
for (int i = 0; i < self.boxCount; i ++) {
//设置填充颜色
CGContextSetFillColorWithColor(context, [self.dotColor colorWithAlphaComponent:[self.dotAlphas[i] floatValue]].CGColor);
CGRect rect = [self getBoxRect:i size:bounds.size];
//圆心的y坐标
float cy = CGRectGetMidY(rect);
//圆心的x坐标
float cx = CGRectGetMidX(rect);
//半径
float half = self.dotRadius * [self.dotScans[i] floatValue];
//添加一个圆
CGContextAddArc(context, cx, cy,half, 0, 2 * M_PI, 0);
//绘制填充
CGContextDrawPath(context, kCGPathFill);
}
}
4、然后在drawRect:中绘制
-(void)drawRect:(CGRect)rect{
CGContextRef context = UIGraphicsGetCurrentContext();
CGSize size = self.frame.size;
[self drawBorder:context size:size];
[self drawDot:context size:size];
}
5、试试效果
到这里,基本上的效果已经可以看到了。
由于之前加了IB_DESIGNABLE,所以我们可以在xib中直接预览和修改参数:
6、改变文字
经过前面几个步骤,视图效果出来了,但是圆点始终是充满所有方框的,现在我们需要根据text的改变,改变圆点的显示个数(只需要改变一下drawDot: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 < MIN(self.text.length, self.boxCount); i ++) {
//设置填充颜色
CGContextSetFillColorWithColor(context, self.dotColor.CGColor);
//圆心的x坐标
float cx = size.width * i / self.boxCount + half;
//添加一个圆
CGContextAddArc(context, cx, cy, self.dotRadius, 0, 2 * M_PI, 0);
//绘制填充
CGContextDrawPath(context, kCGPathFill);
}
}
看看效果:
以上,密码框的基础功能已经实现,这篇文章也告一段落。
下一篇文章,要做的是给圆点加上出现和消失的动画。