iOS开发——实用技术OC篇&事件处理详解
事件处理详解

一:事件处理
事件处理常见属性:
事件类型
- @property(nonatomic,readonly) UIEventType type;
- @property(nonatomic,readonly) UIEventSubtype subtype;
事件产生的时间
- @property(nonatomic,readonly) NSTimeInterval timestamp;
事件传递
- hitTest:withEvent:
SWIFT
func hitTest(_ point: CGPoint, withEvent event: UIEvent?) -> UIView?
OBJECTIVE-C
- (UIView *)hitTest:(CGPoint)point
withEvent:(UIEvent *)event
- pointInside:withEvent:
SWIFT
func pointInside(_ point: CGPoint,
withEvent event: UIEvent?) -> a href="" Bool /a
OBJECTIVE-C
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
事件传递方法的简单实用:
事件传递的时候调用
- 什么时候调用:当事件传递给控件的时候,就会调用控件的这个方法,去寻找最合适的view
- 作用:寻找最合适的view
// point:当前的触摸点,point这个点的坐标系就是方法调用者
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// 调用系统的做法去寻找最合适的view,返回最合适的view
UIView *fitView = [super hitTest:point withEvent:event];
// NSLog(@"fitView--%@",fitView);
return fitView;
}
// 作用:判断当前这个点在不在方法调用者(控件)上
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return YES;
}
事件传递底层的实现:
如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件(掌握)
- 如何找到最合适的控件来处理事件?
- 自己是否能接收触摸事件?
- 触摸点是否在自己身上?
- 从后往前遍历子控件数组,重复前面的两个步骤
- 如果没有符合条件的子控件,那么就自己最适合处理
// 点击黄色视图 -》 事件 -》 UIApplication -> UIWindow
// 因为所有的视图类都是继承BaseView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
NSLog(@"%@--hitTest",[self class]);
// return [super hitTest:point withEvent:event];
// 1.判断当前控件能否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
// 2. 判断点在不在当前控件
if ([self pointInside:point withEvent:event] == NO) return nil;
// 3.从后往前遍历自己的子控件
NSInteger count = self.subviews.count;
; i >= ; i--) {
UIView *childView = self.subviews[i];
// 把当前控件上的坐标系转换成子控件上的坐标系
CGPoint childP = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childP withEvent:event];
if (fitView) { // 寻找到最合适的view
return fitView;
}
}
// 循环结束,表示没有比自己更合适的view
return self;
}
关于事件传递的底层原理和方法的实现:
事件响应:(响应者链)
响应者链条:是由多个响应者对象连接起来的链条
作用:能很清楚的看见每个响应者之间的联系,并且可以让一个事件多个对象处理。
响应者对象:能处理事件的对象

事件传递的完整过程
- 1> 先将事件对象由上往下传递(由父控件传递给子控件),找到最合适的控件来处理这个事件。
- 2> 调用最合适控件的touches….方法
- 3> 如果调用了[super touches….];就会将事件顺着响应者链条往上传递,传递给上一个响应者
- 4> 接着就会调用上一个响应者的touches….方法
重点:如何判断上一个响应者
- 1> 如果当前这个view是控制器的view,那么控制器就是上一个响应者
- 2> 如果当前这个view不是控制器的view,那么父控件就是上一个响应者
二:触摸事件
各个方法的解释

UITouch相关属性:
触摸产生时所处的窗口
- @property(nonatomic,readonly,retain) UIWindow *window;
触摸产生时所处的视图
- @property(nonatomic,readonly,retain) UIView *view;
短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
- @property(nonatomic,readonly) NSUInteger tapCount;
记录了触摸事件产生或变化时的时间,单位是秒
- @property(nonatomic,readonly) NSTimeInterval timestamp;
当前触摸事件所处的状态
- @property(nonatomic,readonly) UITouchPhase phase;
方法:
- - (CGPoint)locationInView:(UIView *)view;
- 返回值表示触摸在view上的位置
- 这里返回的位置是针对view的坐标系的(以view的左上角为原点(0, 0))
- 调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
- - (CGPoint)previousLocationInView:(UIView *)view;
该方法记录了前一个触摸点的位置
UIView不接收触摸事件的三种情况
不接收用户交互
- userInteractionEnabled = NO
隐藏
- hidden = YES
透明
- alpha = 0.0 ~ 0.01
提示:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的
实现UIView的拖动:
OC&Swift版
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint curP = [touch locationInView:self];
CGPoint preP = [touch previousLocationInView:self];
CGFloat offsetX = preP.x - curP.x;
CGFloat offsetY = preP.y - curP.y;
self.transform = CGAffineTransformTranslate(self.transform, -offsetX, -offsetY);
} }
--------------------swift-----------------------
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
var touch:UITouch = touches(AnyObject)
var preP:CGPoint = touch.locationInView(self)
var curP:CGPoint = touch.previousLocationInView(self)
var ofX = curP.x - preP.x
var ofY = curP.y - preP.y
self.transform = CGAffineTransformTranslate(self.transform, ofX, ofY)
}
触摸事件简单介绍:
// 当手指开始触摸view
// NSArray,字典,NSSet(无序)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"%ld", touches.count);
NSLog(@"%s",__func__);
}
// 当手指在view上移动的时候
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"%s",__func__);
}
// 当手指离开这个view的时候
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
// 当触摸事件被打断的时候调用(电话打入)
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}
三:gestureReginazation
各个方法的解释

UIView拖动
OC&Swift版
@interface ViewController ()
@property (weak, nonatomic) IBOutlet iCocosView *dragView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// self.view.transform = CGAffineTransformTranslate(self.view.transform, 100, 100);
/**
为对应的View创建并且添加手势和手势监听方法
*/
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(Drag:)];
[self.dragView addGestureRecognizer:pan];
}
/**
* 实现手势监听方法
*/
-(void)Drag:(UIPanGestureRecognizer *)pan
{
//获取盘的位置
CGPoint p = [pan translationInView:pan.view];
/**
* 使用三步法实现赋值
*/
//根据pan的位置获取pan的中心点
CGPoint center = pan.view.center;
center.x += p.x;
center.y += p.y;
pan.view.center = center;
//根据pan的移动设置对应View的移动
[pan setTranslation:CGPointZero inView:pan.view];
}
------------------swift-----------------------
@IBOutlet weak var dragViews: iCocos!
override func viewDidLoad() {
super.viewDidLoad()
var pan:UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "Drag:")
self.dragViews.addGestureRecognizer(pan)
}
func Drag(pan:UIPanGestureRecognizer)
{
var P:CGPoint = pan.translationInView(pan.view!)
var center:CGPoint = pan.view!.center
center.x += P.x
center.y += P.y
pan.view?.center = center
pan.setTranslation(CGPointZero, inView: pan.view)

------------------------------------------
手势方法简单实用:UIGestureRecognizerDelegate
#pragma mark - 手势代理方法
// 是否允许开始触发手势
//- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
//{
// return NO;
//}
// 是否允许同时支持多个手势,默认是不支持多个手势
// 返回yes表示支持多个手势
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
// 是否允许接收手指的触摸点
//- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
// // 获取当前的触摸点
// CGPoint curP = [touch locationInView:self.imageView];
//
// if (curP.x < self.imageView.bounds.size.width * 0.5) {
// return NO;
// }else{
// return YES;
// }
//}
#pragma mark - 点按手势
- (void)setUpTap
{
// 创建点按手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
tap.delegate = self;
[_imageView addGestureRecognizer:tap];
}
- (void)tap:(UITapGestureRecognizer *)tap
{
NSLog(@"%s",__func__);
}
#pragma mark - 长按手势
// 默认会触发两次
- (void)setUpLongPress
{
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[self.imageView addGestureRecognizer:longPress];
}
- (void)longPress:(UILongPressGestureRecognizer *)longPress
{
if (longPress.state == UIGestureRecognizerStateBegan) {
NSLog(@"%s",__func__);
}
}
#pragma mark - 清扫
- (void)setUpSwipe
{
// 默认轻扫的方向是往右
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
swipe.direction = UISwipeGestureRecognizerDirectionUp;
[self.imageView addGestureRecognizer:swipe];
// 如果以后想要一个控件支持多个方向的轻扫,必须创建多个轻扫手势,一个轻扫手势只支持一个方向
// 默认轻扫的方向是往右
UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
[self.imageView addGestureRecognizer:swipeDown];
}
- (void)swipe
{
NSLog(@"%s",__func__);
}
#pragma mark - 旋转手势
- (void)setUpRotation
{
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];
rotation.delegate = self;
[self.imageView addGestureRecognizer:rotation];
}
// 默认传递的旋转的角度都是相对于最开始的位置
- (void)rotation:(UIRotationGestureRecognizer *)rotation
{
self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation.rotation);
// 复位
rotation.rotation = ;
// 获取手势旋转的角度
NSLog(@"%f",rotation.rotation);
}
#pragma mark - 捏合
- (void)setUpPinch
{
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
pinch.delegate = self;
[self.imageView addGestureRecognizer:pinch];
}
- (void)pinch:(UIPinchGestureRecognizer *)pinch
{
self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinch.scale, pinch.scale);
// 复位
pinch.scale = ;
}
#pragma mark - 拖拽
- (void)setUpPan
{
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self.imageView addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)pan
{
// 获取手势的触摸点
CGPoint curP = [pan locationInView:self.imageView];
// 移动视图
// 获取手势的移动,也是相对于最开始的位置
CGPoint transP = [pan translationInView:self.imageView];
self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, transP.x, transP.y);
// 复位
[pan setTranslation:CGPointZero inView:self.imageView];
NSLog(@"%@",NSStringFromCGPoint(curP));
}
手势状态:
statetypedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
// 没有触摸事件发生,所有手势识别的默认状态
UIGestureRecognizerStatePossible,
// 一个手势已经开始但尚未改变或者完成时
UIGestureRecognizerStateBegan,
// 手势状态改变
UIGestureRecognizerStateChanged,
// 手势完成
UIGestureRecognizerStateEnded,
// 手势取消,恢复至Possible状态
UIGestureRecognizerStateCancelled,
// 手势失败,恢复至Possible状态
UIGestureRecognizerStateFailed,
// 识别到手势识别
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
};
四:加速计:(运动)


- (void)orientationChanged:(NSNotification *)notification {
// Respond to changes in device orientation
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake)
{
// User was shaking the device. Post a notification named "shake."
[[NSNotificationCenter defaultCenter] postNotificationName:@"shake" object:self];
}
}
五:远程控制

注册:
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.playCommand addTargetUsingBlock:^(MPRemoteCommandEvent *event) {
// Begin playing the current track.
[[MyPlayer sharedPlayer] play];
}
使用
- (void)configureNowPlayingInfo:(MPMediaItem*)item{
MPNowPlayingInfoCenter* info = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary* newInfo = [NSMutableDictionary dictionary];
NSSet* itemProperties = [NSSet setWithObjects:MPMediaItemPropertyTitle,
MPMediaItemPropertyArtist,
MPMediaItemPropertyPlaybackDuration,
MPNowPlayingInfoPropertyElapsedPlaybackTime,
nil];
[item enumerateValuesForProperties:itemProperties
usingBlock:^(NSString *property, id value, BOOL *stop) {
[newInfo setObject:value forKey:property];
}];
info.nowPlayingInfo = newInfo;
}
iOS开发——实用技术OC篇&事件处理详解的更多相关文章
- iOS开发——多线程OC篇&多线程详解
多线程详解 前面介绍了多线程的各种方式及其使用,这里补一点关于多线程的概念及相关技巧与使用,相信前面不懂的地方看了这里之后你就对多线程基本上没有什么问题了! 1——首先ios开发多线程中必须了解的概念 ...
- ios开发——实战OC篇&FMDB详解
FMDB详解 前一篇文章中我们介绍的SQLite的使用,在iOS中原生的SQLite API在使用上相当不友好. 于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.Plausibl ...
- iOS开发——屏幕适配篇&Masonry详解
Masonry详解 前言 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-ip ...
- iOS开发——实用技术OC篇&单例模式的实实现(ACR&MRC)
单例模式的实实现(ACR&MRC) 在iOS开发中单例模式是一种非常常见的模式,虽然我们自己实现的比较少,但是,系统却提供了不少的到来模式给我们用,比如最常见的UIApplication,No ...
- iOS开发——实用技术OC篇&简单抽屉效果的实现
简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一 ...
- ios开发——实用技术OC篇&地图与定位
地图与定位 11.1 iOS定位服务 11.2 iOS地图 11.3 Web地图 1 iOS定位服务 iOS中有三个定位服务组件: Wifi定位,通过查询一个Wifi路由器的地理位置的信息.比较省电, ...
- iOS开发——实用技术OC篇&8行代码教你搞定导航控制器全屏滑动返回效果
8行代码教你搞定导航控制器全屏滑动返回效果 前言 如果自定了导航控制器的自控制器的leftBarButtonItem,可能会引发边缘滑动pop效果的失灵,是由于 self.interactivePop ...
- ios开发——实用技术OC篇》倒计时实现的两种方法
倒计时实现的两种方法 timeFireMethod函数,timeFireMethod进行倒计时的一些操作,完成时把timer给invalidate掉就ok了,代码如下: secondsCountDow ...
- iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)
iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController) 前面我们介绍了StoryBoard这个新技术,和纯技术 ...
随机推荐
- C++ 串
♣ string 的基类basic_string中没有虚函数,它无意成为基类.更像是为了处理字符相关的问题而专门提供的一个工具及操作方法.如:想要在一个字符串str1中查找str2,没必要每次都去写K ...
- 解决Ubuntu系统的每次开机重启后,resolv.conf清空的问题
问题情况描述如下: 普及知识: /etc/resolv.conf ,其实是一个Link .它其实指向的是 /run/resolvconf/resolv.conf. Ubuntu 有一个 reso ...
- 使用IIS6.0遇到问题后,常用的几种解决方法
1.检查 .Net Framework,是否安装完全,不确定的情况下使用:aspnet_regiis.exe -i 或者 aspnet_regiis.exe -r 2.检查 IIS 6.0 其它相关配 ...
- MYSQL数据库性能调优之六:备份
增量备份
- ext 参考资料
http://extjs.org.cn/ 中文网站 http://www.sencha.com/ 英文网站 http://www.qeefee.com 个人总结
- 如何通过写一个chrome扩展启动本地程序
@(编程) [toc] 本文介绍如何利用Chrome 的插件, 从我们的一个网站中启动一个我们的本地程序.本文的环境是windows10,本文的例子是通过点击网页上的一个button,调用本地的wor ...
- LeetCode258:Add Digits
Given a non-negative integer num, repeatedly add all its digits until the result has only one digit. ...
- How Tomcat Works(十八)
在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...
- 【Oracle 函数索引】一次数据库的优化过程
[问题]表里数据2万条,查询执行时间 818087.38 ms(12分钟). SQL语句如下:select F1,F2,F3,F4 from t_sms_g_send t left joi ...
- ecshop读写分离
1.配置文件设置 $db_name = "ecshop"; $prefix = "ecs_"; $timezone = "Europe/Berlin& ...