
1.jpeg
分析界面
- 當(dāng)手指在上面移動時,當(dāng)移動到一個按鈕范圍內(nèi)當(dāng)中, 它會把按鈕給成為選中的狀態(tài).
2.并且把第一個選中的按鈕當(dāng)做一個線的起點,當(dāng)手指移動到某個按鈕上時,就會添加一根線到選中的那妞上.
3.當(dāng)手指松開時,所有按鈕取消選中.所有的線都清空.
實現(xiàn)思路:(自定義view,以后可以直接在項目中用)
先判斷點前手指在不在當(dāng)前的按鈕上.如果在按鈕上,就把當(dāng)前按鈕成為選中狀態(tài).
并且把當(dāng)前選中的按鈕添加到一個數(shù)組當(dāng)中.如果當(dāng)前按鈕已經(jīng)是選中狀態(tài),就不需要再添加到數(shù)組中了.
每次移動時,都讓它進行重繪.
在繪圖當(dāng)中,遍歷出所有的選中的按鈕,
判斷數(shù)組當(dāng)中的第一個無素,如果是第一個,那么就把它設(shè)為路徑的起點.其它都在添加一根線到按鈕的圓心.
如果當(dāng)前點不在按鈕上.那么就記錄住當(dāng)前手指所在的點.直接從起點添加一根線到當(dāng)前手指所在的點.
實現(xiàn)步驟:
1.搭建界面
界面是一個九宮格的布局.九宮格實現(xiàn)思路.
先確定有多少列 cloum = 3;
計算出每列之間的距離
計算為: CGFloat margin = (當(dāng)前View的寬度 - 列數(shù) * 按鈕的寬度) / 總列數(shù) + 1
每一列的X的值與它當(dāng)前所在的行有關(guān)
當(dāng)前所在的列為:curColum = i % cloum
每一行的Y的值與它當(dāng)前所在的行有關(guān).
當(dāng)前所在的行為:curRow = i / cloum
每一個按鈕的X值為, margin + 當(dāng)前所在的列 * (按鈕的寬度+ 每個按鈕之間的間距)
每一個按鈕的Y值為 當(dāng)前所在的行 * (按鈕的寬度 + 每個按鈕之間的距離)
具體代碼為:
總列數(shù)
int colum = 3;
每個按鈕的寬高
CGFloat btnWH = 74;
每個按鈕之間的距離
CGFloat margin = (self.bounds.size.width - colum * btnWH) / (colum + 1);
for(int i = 0; i < self.subviews.count; i++ ){
當(dāng)前所在的列
int curColum = i % colum;
當(dāng)前所在的行
int curRow = i / colum;
CGFloat x = margin + (btnWH + margin) * curColum;
CGFloat y = (btnWH + margin) * curRow;
取出所有的子控件
UIButton *btn = self.subviews[i];
btn.frame = CGRectMake(x, y, btnWH, btnWH);
}
2.監(jiān)聽手指在上面的點擊,移動,松開都需要做操作.
2.1在手指開始點擊屏幕時,如果當(dāng)前手指所在的點在按鈕上, 那就讓按鈕成為選中狀態(tài).
所以要遍歷出所有的按鈕,判斷當(dāng)前手指所在的點在不在按鈕上,
如何判斷當(dāng)前點在不在按鈕上?
當(dāng)前方法就是判斷一個點在不在某一個區(qū)域,如果在的話會返回Yes,不在的話,返回NO.
CGRectContainsPoint(btn.frame, point)
在手指點擊屏幕的時候,要做的事分別有
1.獲取當(dāng)前手指所在的點.
UITouch *touch = [touches anyObject];
CGPoint curP = [touch locationInView:self];
2.判斷當(dāng)前點在不在按鈕上.
for (UIButton *btn in self.subviews) {
if (CGRectContainsPoint(btn.frame, point)) {
return btn;
}
}
3.如果當(dāng)前點在按鈕上,并且當(dāng)前按鈕不是選中的狀態(tài).
那么把當(dāng)前的按鈕成為選中狀態(tài).
并且把當(dāng)前的按鈕添加到數(shù)組當(dāng)中.
2.2 當(dāng)手指在移動的時也需要判斷.
判斷當(dāng)前點在按鈕上,并且當(dāng)前按鈕不是選中的狀態(tài).
那么把當(dāng)前的按鈕成為選中狀態(tài).
并且把當(dāng)前的按鈕添加到數(shù)組當(dāng)中.
在移動的時候做重繪的工作.
2.3 當(dāng)手指離開屏幕時.
取出所有的選中按鈕,把所有選中按鈕取消選中狀態(tài).
清空選中按鈕的數(shù)組.
繪重繪的工作.
3. 在繪圖方法當(dāng)中.
創(chuàng)建路徑
遍歷出有的選中按鈕.如果是第一個按鈕,把第一個按鈕的中心點當(dāng)做是路徑的起點.
其它按鈕都直接添加一條線,到該按鈕的中心.
遍歷完所有的選中按鈕后.
最后添加一條線到當(dāng)前手指所在的點.
具體代碼如下:
#import "ClockView.h"
@interface ClockView()
/**
* 選中的按鈕數(shù)組.
*/
@property(nonatomic,strong)NSMutableArray *selectBtn;
/**
* 當(dāng)前手指移動的點
*/
@property(nonatomic,assign)CGPoint curP;
@end
@implementation ClockView
//懶加載數(shù)組.
-(NSMutableArray *)selectBtn{
if (_selectBtn == nil) {
_selectBtn = [NSMutableArray array];
}
return _selectBtn;
}
-(void)awakeFromNib{
//初始化
[self setUP];
}
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
//初始化
[self setUP];
}
return self;
}
//初始化
- (void)setUP{
for (int i = 0; i < 9; i++) {
//添加按鈕
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
//添加按鈕時設(shè)置一個Tag以便記錄每一個選中的按鈕
btn.tag = i;
//讓按鈕不能夠接受事件,原因是當(dāng)前按鈕會攔截事件.
btn.userInteractionEnabled = NO;
//設(shè)置圖片
[btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
//設(shè)置選中狀態(tài)的下圖片
[btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
[self addSubview:btn];
}
}
/**
* 獲取當(dāng)前手指所在的點
*
* @param touches touches集合
*
* @return 當(dāng)前手指所在的點.
*/
- (CGPoint)getCurrentPoint:(NSSet *)touches{
UITouch *touch = [touches anyObject];
return [touch locationInView:self];
}
/**
* 判斷一個點在不在按鈕上.
*
* @param point 當(dāng)前點
*
* @return 如果在按鈕上, 返回當(dāng)前按鈕, 如果不在返回nil.
*/
- (UIButton *)btnRectContainsPoint:(CGPoint)point{
for (UIButton *btn in self.subviews) {
if (CGRectContainsPoint(btn.frame, point)) {
//在按鈕上.返回當(dāng)前按鈕
return btn;
}
}
return nil;
}
//手指點擊時讓按鈕成選中狀態(tài)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//判斷當(dāng)前手指在不在按鈕上,如果在按鈕上, 讓按鈕成為選中狀態(tài).
//1.獲取當(dāng)前手指所在的點
CGPoint curP = [self getCurrentPoint:touches];
//2.判斷當(dāng)前手指所在的點在不在按鈕上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn && btn.selected == NO) {//如果按鈕已經(jīng)是選中狀態(tài),就不讓它再添加到數(shù)組當(dāng)中
//讓按鈕成為選中狀態(tài)
btn.selected = YES;
//把選中按鈕添加到數(shù)組當(dāng)中
[self.selectBtn addObject:btn];
}
}
//手指移動時,按鈕選中,連線到當(dāng)前選中的按鈕
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
//判斷當(dāng)前手指在不在按鈕上,如果在按鈕上, 讓按鈕成為選中狀態(tài).
//1.獲取當(dāng)前手指所在的點
CGPoint curP = [self getCurrentPoint:touches];
//2.判斷當(dāng)前手指所在的點在不在按鈕上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn && btn.selected == NO) {//如果按鈕已經(jīng)是選中狀態(tài),就不讓它再添加到數(shù)組當(dāng)中
//讓按鈕成為選中狀態(tài)
btn.selected = YES;
//把選中按鈕添加到數(shù)組當(dāng)中
[self.selectBtn addObject:btn];
}
//每次做一次重繪.
[self setNeedsDisplay];
//記錄當(dāng)前手指移動的點.
self.curP = curP;
}
//手指松開時,按鈕取消選中狀態(tài),清空所有的連線.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.selectBtn.count) {
//1.取消所有選中的按鈕,查看選中按鈕的順序
NSMutableString *str = [NSMutableString string];
for (UIButton *btn in self.selectBtn) {
[str appendFormat:@"%ld",btn.tag];
btn.selected = NO;
}
//2.清空所有的連線.
[self.selectBtn removeAllObjects];
//3.重繪
[self setNeedsDisplay];
//查看是否是第一次設(shè)置密碼
NSString *keyPwd = [[NSUserDefaults standardUserDefaults] objectForKey:@"keyPwd"];
if (!keyPwd) {
[[NSUserDefaults standardUserDefaults] setObject:str forKey:@"keyPwd"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(@"第一次輸入密碼");
} else {
if ([keyPwd isEqualToString:str]) {
NSLog(@"密碼正確");
UIAlertView *alertV = [[UIAlertView alloc] initWithTitle:@"手勢輸入正確" message:nil delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
[alertV show];
} else {
NSLog(@"密碼錯誤");
UIAlertView *alertV = [[UIAlertView alloc] initWithTitle:@"手勢輸入錯誤" message:nil delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
[alertV show];
}
}
NSLog(@"選中按鈕順序為:%@",str);
}
}
//布局子控件
- (void)layoutSubviews{
[super layoutSubviews];
//總列數(shù)
int cloumn = 3;
CGFloat btnWH = 74;
//每列之間的間距
CGFloat margin = (self.bounds.size.width - cloumn * btnWH) / (cloumn + 1);
//當(dāng)前所在的列
int curClounm = 0;
//當(dāng)前所在的行
int curRow = 0;
CGFloat x = 0;
CGFloat y = 0;
//取出所有的控件
for (int i = 0; i < self.subviews.count; i++) {
curClounm = i % cloumn;
curRow = i / cloumn;
x = margin + (margin + btnWH) * curClounm;
y = (margin +btnWH) * curRow;
UIButton *btn = self.subviews[i];
//設(shè)置按鈕的尺寸位置
btn.frame = CGRectMake(x, y, btnWH, btnWH);
}
}
- (void)drawRect:(CGRect)rect {
//如果數(shù)組當(dāng)中沒有元素,就不讓它進行繪圖.直接返回.
if(self.selectBtn.count <= 0) return;
//創(chuàng)建路徑.
UIBezierPath *path = [UIBezierPath bezierPath];
//取出所有保存的選中按鈕連線.
for(int i = 0; i < self.selectBtn.count;i++){
UIButton *btn = self.selectBtn[i];
//判斷當(dāng)前按鈕是不是第一個,如果是第一個,把它的中心設(shè)置為路徑的起點.
if(i == 0){
//設(shè)置起點.
[path moveToPoint:btn.center];
}else{
//添加一根線到當(dāng)前按鈕的圓心.
[path addLineToPoint:btn.center];
}
}
//連完先中的按鈕后, 在選中按鈕之后,添加一根線到當(dāng)前手指所在的點.
[path addLineToPoint:self.curP];
//設(shè)置顏色
[[UIColor redColor] set];
//設(shè)置線寬
[path setLineWidth:10];
//設(shè)置線的連接樣式
[path setLineJoinStyle:kCGLineJoinRound];
//繪制路徑.
[path stroke];
}
@end