1.响应者对象
- 在IOS中,只有继承了UIResponder的对象才能接收并处理事件,我们称之为“响应者对象”
- UIApplication,UIViewController,UIView都继承自UIResponder,因此他们都是响应者对象,都能够接收并处理事件
UIResponder内部提供了一下方法来处理事件
#import "FRView.h"
@implementation FRView
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
//手指在view上松开的时候调用
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
//意外终止(如被电话打断)
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
@end
2.手势的几个属性
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch* touch=touches.anyObject;
//NSLog(@"%ld",touch.tapCount);//快速点击的次数
//NSLog(@"%ld",touch.phase);//触摸的阶段
NSLog(@"%@",touch.window);//获取触摸事件产生的窗口
NSLog(@"%@",[UIApplication sharedApplication].keyWindow);//获取主窗口
NSLog(@"%@",self.window);//获取当前view所在的窗口
NSLog(@"%@",touch.view);//获取当前view
NSLog(@"%@",self);//获取自己
CGPoint p=[touch locationInView:self];//在自己这个self中触摸的位置
CGPoint p1=[touch locationInView:self.superview];//在父控件这个self中触摸的位置
NSLog(@"%@",NSStringFromCGPoint(p1));
}
//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch* touch=touches.anyObject;
CGPoint p=[touch locationInView:self];
NSLog(@"%@当前点",NSStringFromCGPoint(p));//当前点
CGPoint lastP=[touch previousLocationInView:self];
NSLog(@"%@上一个点",NSStringFromCGPoint(lastP));//上一个点
}
3.单点触摸
#import "FRView.h"
@implementation FRView
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//获取触摸对象
UITouch* touch=touches.anyObject;
CGPoint point=[touch locationInView:self.superview];//获取绿色的view父控件的点的位置
//让绿色的view的中心等于手指的位置
self.center=point;
}
//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//获取触摸对象
UITouch* touch=touches.anyObject;
//获取当前的位置
CGPoint point=[touch locationInView:self.superview];//获取view的父控件的点
//获取上一个点的位置
CGPoint lastPoint=[touch previousLocationInView:self.superview];
//计算偏移量
CGFloat offsetX=point.x-lastPoint.x;
CGFloat offsetY=point.y-lastPoint.y;
//让绿色的view的center在自己的位置基础上+偏移量
self.center=CGPointMake(self.center.x+offsetX, self.center.y+offsetY);
//让绿色的view的中心等于手指位置
//self.center=point;
}
//手指在view上松开的时候调用
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
}
//意外终止(如被电话打断)
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
}
@end
效果:view被拖动
4.多点触摸
将当前view的类指定为FRView
#import "FRView.h"
@interface FRView()
@property(nonatomic,strong)NSArray *images;
@end
@implementation FRView
#pragma mark --------懒加载数据-------
//重写images的get方法
-(NSArray*)images{
if (!_images) {
_images=@[[UIImage imageNamed:@"spark_blue"],[UIImage imageNamed:@"spark_green"]];
}
return _images;
}
//手指接触到这个view时调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//touchs作为集合有几个元素索命有几个触摸点
NSLog(@"%ld",touches.count);
[self addimageView:touches];
}
//手指在这个view移动的时候调用
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self addimageView:touches];
}
-(void)addimageView:(NSSet<UITouch *> *)touches {
int i=0;
for (UITouch* touch in touches) {
//获取手指的位置
CGPoint point=[touch locationInView:touch.view];//触摸的view
//创建一个imageview
UIImageView* imageView= [[UIImageView alloc]initWithImage:self.images[i]];
//设置imageview的中心为手指的位置
imageView.center=point;
//把imageview加到当前的大view上
[self addSubview:imageView];
//动画移除当前点,2秒内imageview的透明度为零然后移除
[UIView animateWithDuration:2 animations:^{
imageView.alpha=0;
} completion:^(BOOL finished) {
[imageView removeFromSuperview];
}];
i++;
}
}
//手指在view上松开的时候调用
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
}
//意外终止(如被电话打断)
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
}
@end
5.时间的产生和传递
6.手势解锁案例
这是个冗长的案例,中规中矩
在storyboard中创建一个view,对应FRView
FRView.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface FRView : UIView
//创建一个自定义block
@property(nonatomic,copy)BOOL (^passwordBlock)(NSString*);
@end
NS_ASSUME_NONNULL_END
FRView.m
#import "FRView.h"
#define kButtonCount 9
@interface FRView()
@property(nonatomic,strong)NSMutableArray* buttons;//9个按钮
@property(nonatomic,strong)NSMutableArray* lineButtons;//需要连线的按钮个按钮
@property(nonatomic,assign)CGPoint currentPoint;//当前的手指位置
@end
@implementation FRView
#define mark ------懒加载数据--------
//重写buttons属性的get方法
-(NSMutableArray*)buttons{
if (!_buttons) {
_buttons=[NSMutableArray array];
//添加9个按钮
for (int i=0; i<kButtonCount; i++) {
//创建一个button
UIButton* button=[[UIButton alloc]init];
//给button设置一个tag
button.tag=i;
//给button设置一个正常状态下的背景图
[button setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
//设置button高亮(选中状态)
[button setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
//设置button错误的图片(可用状态)
[button setBackgroundImage:[UIImage imageNamed:@"gesture_node_error"] forState:UIControlStateDisabled];
//禁用button的用户交互
button.userInteractionEnabled=NO;
[self addSubview:button];
//把循环创建的button添加到数组中去
[_buttons addObject:button];
//[self.buttons addObject:button];
}
}
return _buttons;
}
//初始化lineButtons
-(NSMutableArray*)lineButtons{
if (!_lineButtons) {
_lineButtons=[NSMutableArray array];
}
return _lineButtons;
}
//当手指触摸到应用是
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//获取触摸的点
UITouch* touch=touches.anyObject;
//获取手指的位置,touch所在view的位置
CGPoint point=[touch locationInView:touch.view];
for (int i=0; i<self.buttons.count; ++i) {
//获取button
UIButton* button=self.buttons[i];
//如果button的frame包含这个点
if (CGRectContainsPoint(button.frame, point)) {
//让按钮亮起来
button.selected=YES;
//高亮的按钮添加到需要划线的数组中
[self.lineButtons addObject:button];
}
}
}
//设置手指离开时候的手势
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//修改最后手指的位置为需要连线的最后一个按钮的中心,解决最后一根线多出来的问题
self.currentPoint=[[self.lineButtons lastObject]center];
//重绘
[self setNeedsDisplay];
//让所有需要划线的button都变成错误的样式
for (int i=0; i<self.lineButtons.count; ++i) {
//获取button
UIButton* button=self.lineButtons[i];
//让button变成错误状态的时候需要取消选中状态
button.selected=NO;
//让button变成不可用状态
button.enabled=NO;
}
//拼接密码
NSString* password=@"";
for (int i=0; i<self.lineButtons.count; ++i) {
//获得按钮
UIButton* button=self.lineButtons[i];
//拼接密码
password=[password stringByAppendingString:[NSString stringWithFormat:@"%ld", button.tag]];
}
//判断password里面是否有值
if (self.passwordBlock) {
if (self.passwordBlock(password)) {
NSLog(@"密码正确");
}else{
NSLog(@"密码错误");
}
}
NSLog(@"%@",password);
//关闭用户交互
[self setUserInteractionEnabled:NO];
//间隔一段时间再清空所有按钮
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//开启用户交互
[self setUserInteractionEnabled:YES];
//清空所有按钮
[self clear];
});
}
//清空所有按钮的方法
-(void)clear{
for (int i=0; i<self.buttons.count; i++) {
UIButton* button=self.buttons[i];
//取消按钮的高亮状态(选中状态)
button.selected=NO;
//让按钮取消错误的样式
button.enabled=YES;
}
//清空所有线条
[self.lineButtons removeAllObjects];
//重绘一下
[self setNeedsDisplay];
}
//设置手指在移动时候的的手势
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//获取触摸对象
UITouch* touch=touches.anyObject;
//获取手指的最新位置
CGPoint point=[touch locationInView:touch.view];
//给全局属性的手指位置赋值
self.currentPoint=point;
for (int i=0; i<self.buttons.count; ++i) {
UIButton* button=self.buttons[i];
//判断手指是否在某个按钮的范围之内
if (CGRectContainsPoint(button.frame, point)) {
button.selected=YES;
//判断,如果已经加到了数组当中,那么不在去添加
if (![self.lineButtons containsObject:button]) {
//高亮的按钮添加到需要划线的数组中
[self.lineButtons addObject:button];
}
}
}
//重绘自己
[self setNeedsDisplay];
}
//按钮间的连线
- (void)drawRect:(CGRect)rect{
//如果没有起点则不要绘制,直接返回
if (!self.lineButtons.count) {
return;
}
//创建路径
UIBezierPath* path=[UIBezierPath bezierPath];
for (int i=0; i<self.lineButtons.count; ++i) {
//获取button
UIButton* button=self.lineButtons[i];
//如果是起始点则让画起点到这个位置的中心,如果不是起点则话重点到这个位置的中心
if (i==0) {
[path moveToPoint:button.center];
}else{
[path addLineToPoint:button.center];
}
}
//连线到手指的位置
[path addLineToPoint:self.currentPoint];
//设置颜色
[[UIColor whiteColor]set];
//设置线宽
[path setLineWidth:10];
//设置连接处的样式
[path setLineJoinStyle:kCGLineJoinRound];
[path setLineCapStyle:kCGLineCapRound];
//渲染线条
[path stroke];
}
//,排列子视图,计算9宫格
- (void)layoutSubviews{
[super layoutSubviews];
CGFloat w=74;
CGFloat h=w;
int colCount=3;
CGFloat margin=(self.frame.size.width-3*w)/4;
for (int i=0; i<kButtonCount; ++i) {
//计算九宫格位置
CGFloat x=(i%colCount)*(margin+w)+margin;
CGFloat y=(i/colCount)*(margin+w)+margin;
[self.buttons[i] setFrame:CGRectMake(x, y, w, h)];
}
}
@end
ViewController.m
#import "ViewController.h"
#import "FRView.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet FRView *passowrdView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//设置ViewController背景图片,直接使用UIColor的colorWithPatterImage背景色方法
self.view.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed: @"Home_refresh_bg"]];
//密码
//NSString* strpassword=@"012";
self.passowrdView.passwordBlock=^(NSString* strpwd){
if ([strpwd isEqualToString:@"012"]) {
return YES;
}else{
return NO;
}
};
}
@end
效果,截图不能显示交互
代码在这里下载,这次没有过程……
案例代码下载