IOS 触摸事件
来源:互联网 发布:linux ubuntu 服务器版 编辑:程序博客网 时间:2024/05/19 17:03
1.事件的产生传递
产生
当用户触摸屏幕的时候,UIApplication监听到触摸事件,会生成UIEvent传递给UIWindow,然后向下传递事件
传递
事件的传递是由外层传递给内层view的,产生事件后会寻找事件的消费者,来消费事件,如何寻找事件消费者呢
主要涉及的API有:
1.
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;2.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
方法的作用如下:
/* * point:触摸的点,该点的坐标系是相对当前view的 * event:事件 * 返回的view 就是事件的消费者,不返回,由上层调用者处理 * 通俗点说法就是:告诉我摸了谁,返回的view就是被触摸的view,返回空,就是说我和我的子view没有被触摸 */-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ //以下粗略模拟下了默认的处理方法的大概实现 相当于 return [super hitTest:point withEvent:event]; //判断自己能否接收事件 if(!self.userInteractionEnabled||self.hidden||self.alpha<=0.01){ return nil; } //判断点是否落在了当前view的返回内 if(![self pointInside:point withEvent:event]){ return nil; } //判断内部子控件是否有比自己更合适的View for(UIView *childView in self.subviews){ //将点的坐标系转换为子View的坐标系 CGPoint childPoint=[self convertPoint:point toView:childView]; UIView *hitView=[childView hitTest:childPoint withEvent:event]; if(hitView){//如果子View找到了合适的View return hitView; } } return self;//没有找到比自己合适的view,返回自己}/* * 判断点是否落在在自己的范围内 * 如果重写了 (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 需要自己调用,hitTest默认的实现中,调用这个方法,判断点是否落在自己的范围内 */ -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ return YES;}
粗略的概括下,如图:
2.事件的响应
所有UIResponder的子类(UIView,UIViewController)都可以响应触摸方法,确定了最佳的事件响应者之后,会调用事件的响应的方法,消费事件。根据事件的不同阶段会调用响应者的不同方法,相关方法一共4个
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //开始触摸}-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //触摸并移动}-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //所有的触摸手指都离开屏幕}-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //电话等打断触摸时间,一般直接调用触摸结束的方法就可以了 [self touchesEnded:touches withEvent:event];}
3.触摸UITouch
每次触摸都包含下列信息
- 触摸的发生在何处(view,以及其坐标),包括当前的触摸位置和上次的触摸位置
- 触摸处于的阶段
- 点击的次数
- 触摸的发生时间
触摸有生命周期,每个触摸都处于下列的触摸的5个阶段之一
@property(nonatomic,readonly) UITouchPhase phase;//通过这个属性获取触摸所处阶段 //开始触摸 UITouchPhaseBegan, // 触摸开始 UITouchPhaseMoved, // 手指移动 UITouchPhaseStationary, // 手指触摸着屏幕但不移动 UITouchPhaseEnded, // 手指离开屏幕 UITouchPhaseCancelled // 触摸终端
以下为常用方法
UITouch *touch=[touches anyObject]; //获取所处窗口 UIWindow *window=touch.window; //所处view UIView *view=touch.view; //短时间点击屏幕的次数 NSUInteger tapCount=touch.tapCount; //触摸时间(变化时间) NSTimeInterval time=touch.timestamp; //秒 //当前所处view,对应其坐标系的位置点 CGPoint currentPoint=[touch locationInView:touch.view]; //前一个位置的点 CGPoint previousPoint=[touch previousLocationInView:touch.view];
4.涂鸦板
根据手指的移动路径绘制图像
#import "TouchDrawView.h"@implementation TouchDrawView{ UIBezierPath *path;//存储绘制路径}-(void)awakeFromNib{ [super awakeFromNib]; self.multipleTouchEnabled=NO;//禁止多点触摸 path=[UIBezierPath bezierPath]; path.lineWidth=5.0f; path.lineCapStyle=kCGLineCapRound; path.lineJoinStyle=kCGLineJoinRound;}-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [path moveToPoint:[[touches anyObject] locationInView:self]];//起点}-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [path addLineToPoint:[[touches anyObject] locationInView:self]]; [self setNeedsDisplay];}-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [path addLineToPoint:[[touches anyObject] locationInView:self]]; [self setNeedsDisplay];}-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self touchesEnded:touches withEvent:event];}-(void)drawRect:(CGRect)rect{ [[UIColor redColor] setStroke]; [path stroke];}@end
实现的效果图:
平滑算法---样条插值法
样条插值法:在每两个关键点中插入点,使得保留原来的路径的情况下使得画的线更加平滑,前提是必修有原4个参考点,比如现在1,2,3,4点,就可以在2,3之间插入几个点,使得2到3之间更加平滑,但是由于没有处理角度问题,会出现拐角处出现形变。完善思路是根据1,2和3,4形成的两条线之间的夹角判断是否插入值,如果角度偏小不插入。我没有判断夹角直接添加点,使用的话,需要自己完善。1.创建贝塞尔曲线获取点的分类
#import "UIBezierPath+Points.h"#define VALUE(_INDEX_) [NSValue valueWithCGPoint:points[_INDEX_]]@implementation UIBezierPath (Points)void getPointsFromPath(void * __nullable info, const CGPathElement * element){ NSMutableArray *pointsArray=(__bridge NSMutableArray *)(info); CGPathElementType type=element->type; CGPoint *points=element->points; if(type!=kCGPathElementCloseSubpath){ [pointsArray addObject:VALUE(0)]; if(type!=kCGPathElementAddLineToPoint&&type!=kCGPathElementMoveToPoint){ [pointsArray addObject:VALUE(1)]; } } if(type==kCGPathElementAddCurveToPoint){ [pointsArray addObject:VALUE(2)]; }}-(NSArray *)points{ NSMutableArray *points=[NSMutableArray array]; CGPathApply(self.CGPath, (__bridge void * _Nullable)(points), getPointsFromPath); return points;}添加获取贝塞尔曲线平滑的分类
#import "UIBezierPath+Smooth.h"#import "UIBezierPath+Points.h"#define POINT(_INDEX_) [[points objectAtIndex:_INDEX_] CGPointValue]@implementation UIBezierPath (Smooth)-(UIBezierPath *)smoothPath:(int)factor{ NSMutableArray *points=[self.points mutableCopy]; //少于4个点 不做插值 if(points.count<4) return [self copy]; [points insertObject:points[0] atIndex:0]; [points addObject:[points lastObject]]; UIBezierPath *smoothPath=[UIBezierPath bezierPath]; smoothPath.lineWidth=self.lineWidth; [smoothPath moveToPoint:POINT(0)]; [smoothPath addLineToPoint:POINT(1)]; [smoothPath addLineToPoint:POINT(2)]; for(int i=4;i<points.count;i++){ //获取4个控制点 CGPoint p0=POINT(i-3); CGPoint p1=POINT(i-2); CGPoint p2=POINT(i-1); CGPoint p3=POINT(i); for(int j=1;j<factor;j++){ float t=(float)j*(1.0f/(float)factor); float tt=t*t; float ttt=tt*t; CGPoint pi; pi.x=0.5*(2*p1.x+(p2.x-p0.x)*t+(2*p0.x-5*p1.x+4*p2.x-p3.x)*tt+(3*p1.x-p0.x-3*p2.x+p3.x)*ttt); pi.y=0.5*(2*p1.y+(p2.y-p0.y)*t+(2*p0.y-5*p1.y+4*p2.y-p3.y)*tt+(3*p1.y-p0.y-3*p2.y+p3.y)*ttt); [smoothPath addLineToPoint:pi]; } [smoothPath addLineToPoint:p2]; } [smoothPath addLineToPoint:POINT(points.count-1)]; return smoothPath;}@end
0 0
- ios触摸事件四:触摸
- ios 进阶 -- 触摸事件
- IOS触摸事件
- iOS 触摸事件处理
- ios touches、触摸事件
- IOS-触摸事件
- iOS触摸事件处理
- iOS 触摸事件
- iOS触摸事件处理
- ios触摸事件处理
- IOS 触摸事件--1
- iOS中的触摸事件
- iOS触摸事件学习
- iOS触摸事件处理
- iOS触摸事件总结
- iOS触摸事件解析
- iOS触摸事件处理
- ios 中触摸事件
- 低功耗蓝牙(BLE)之概念理解
- 20. 静态区块(Static Blocks)
- 编写串口通信的要注意的地方
- 38.IO流
- C++作业3
- IOS 触摸事件
- 194. Transpose File
- 单调递增子序列(二)(nyoj214)
- Intellij Idea 使用笔记
- 获取字符数方法
- SPOJ 5971 LCM SUM
- 项目实施中CRP的含义,以及各个阶段
- 责任链模式(java语言实现)
- javaweb基于内容的图片搜索引擎(4)_前台检索以及结果