1.效果图
2.storyboard中设置
3.代码实现
#import "keyView.h"
@interface keyView ()
//用来保存移动手指的点
@property (nonatomic,assign)CGPoint point;
/** 存放的都是当前选中的按钮 */
@property (nonatomic, strong) NSMutableArray *selectBtnArray;
@end
@implementation keyView
//懒加载创建selectBtnArray数组
-(NSMutableArray *)selectBtnArray{
if (_selectBtnArray == nil) {
_selectBtnArray = [NSMutableArray array];
}
return _selectBtnArray;
}
//从storyboard中加载view,系统会自动来调用这个方法,可以将程序中一些初始化代码\
放在这个方法里面编写
-(void)awakeFromNib{
//创建9个按钮
for (int i = 0; i < 9; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:@"button1"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"button2"] forState:UIControlStateSelected];
//设置按钮与用户不能交互,点击事件给父控件执行
button.userInteractionEnabled = NO;
//将按钮添加到keyView中
[self addSubview:button];
}
}
//按钮的布局需在layoutSubviews中进行设置, 九宫格算法
-(void)layoutSubviews{
//需调用父类的这个方法
[super layoutSubviews];
int colunm = 3; //列数
CGFloat buttonWH = 74; //按钮的宽高
//按钮之间的空隙
CGFloat margin = (self.frame.size.width - buttonWH * colunm) / (colunm + 1);
int curC = 0;
int curR = 0;
//遍历设置9个按钮的frame
for (int i = 0; i < 9; i++) {
curC = i % colunm;
curR = i / colunm;
CGFloat x = margin + (buttonWH + margin)*curC;
CGFloat y = margin + (buttonWH + margin)*curR;
UIButton *button = self.subviews[i];
button.tag = i; //给每个按钮绑定tag值,方便后面密码区分
button.frame = CGRectMake(x, y, buttonWH, buttonWH);
}
}
//抽取方法,给方法传一个手势,就放回手势的坐标点
-(CGPoint)getTouches:(NSSet *)touches{
UITouch *touch = [touches anyObject];
return [touch locationInView:self];
}
//抽取方法,给方法传坐标点,判断这个点在不在按钮上,如果在就返回这个按钮,不在就返回nil
-(UIButton *)selectButton:(CGPoint)point{
for (UIButton *button in self.subviews)
{
if (CGRectContainsPoint(button.frame, point))
{
return button;
}
}
return nil;
}
//手指开始移动
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CGPoint point = [self getTouches:touches];
UIButton *button = [self selectButton:point];
if (button && button.selected == NO) {
button.selected = YES;
[self.selectBtnArray addObject:button];
}
}
//手指移动过程中
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
CGPoint point = [self getTouches:touches];
self.point = point;
UIButton *button = [self selectButton:point];
if (button && button.selected ==NO) {
button.selected = YES;
[self.selectBtnArray addObject:button];
}
[self setNeedsDisplay];
}
//手指移动结束,离开屏幕
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSMutableString *str = [NSMutableString string];
for (UIButton *button in self.selectBtnArray) {
button.selected = NO;
[str appendFormat:@"%ld",button.tag];
}
[self.selectBtnArray removeAllObjects];
//重绘
[self setNeedsDisplay];
//根据key值在沙盒中取出对应的value
NSString *password = [[NSUserDefaults standardUserDefaults]objectForKey:@"password"];
//如果取出的key为空,那就表示为第一次输入密码,将这一次输入的密码作为默认密码
if (password == nil) {
[[NSUserDefaults standardUserDefaults]setObject:str forKey:@"password"];
//调用synchronize方法,可以同步内存中的缓存和用户默认系统
[[NSUserDefaults standardUserDefaults]synchronize];
}else{
if ([str isEqualToString:password]) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"密码正确" message:nil delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alert show];
}else {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"密码错误" message:@"重新输入" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alert show];
}
}
}
//drawrect方法,绘制连线
-(void)drawRect:(CGRect)rect{
if (self.selectBtnArray.count) {
UIBezierPath *path = [UIBezierPath bezierPath];
for (int i = 0; i < self.selectBtnArray.count; i++) {
UIButton *button = self.selectBtnArray[i];
if (i == 0) {
[path moveToPoint:button.center];
}else
[path addLineToPoint:button.center];
}
[path addLineToPoint:self.point];
[path setLineJoinStyle:kCGLineJoinRound];
[path setLineWidth:10];
[[UIColor redColor]set];
[path stroke];
}
}
@end
for (UIButton *button in self.selectBtnArray) {
button.selected = NO;
[str appendFormat:@"%ld",button.tag];
}
[self.selectBtnArray removeAllObjects];
//重绘
[self setNeedsDisplay];
4.移除或者添加按钮,或者在view上移动时,都必须调用setNeedsDisplay方法,重绘