摇一摇的相关事件, 都是从UIResponder中继承过来的
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
NSLog(@"开始摇一摇");
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
NSLog(@"结束摇一摇");
}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
// 如来电
NSLog(@"摇一摇被取消");
}
触摸开始, 手指按下去 (没有松开)
在一次手势触摸的过程(从按下到松开), 只执行一次
- (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
获取当前的触摸点
UITouch *touch = [touches anyObject];
获取当前触摸的点在self.view上的位置 如果移动也会一直变动
CGPoint point = [touch locationInView:self.view];
获取触摸屏幕时记录的点 只记录触摸的一瞬间
CGPoint prePoint = [touch previousLocationInView:self.view];
视图默认只支持一个点的, 如果要支持多点的触摸, 需要额外配置 添加以下代码
[self.view setMultipleTouchEnabled:YES];
示例:
以下方法实现后 添加视图素材 可以实现触摸屏幕的同时 触摸的地方显示素材光点
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSArray<UITouch *> *touchArr = [touches allObjects];
for (UITouch *touch in touchArr) {
// -------- 2. 获取该获取点在根视图上的位置 --------
CGPoint point = [touch locationInView:self.view];
NSLog(@"%@", NSStringFromCGPoint(point));
// -------- 3. 添加UIImage控件 --------
UIImage *image = [UIImage imageNamed:@"spark_green"];
UIImageView *imageview = [[UIImageView alloc] initWithImage:image];
imageview.center = point;
[self.view addSubview:imageview];
// -------- 4. 逐渐消失的动画, 动画完之后移除 --------
[UIView animateWithDuration:2.0 animations:^{
imageview.alpha = 0.0;
} completion:^(BOOL finished) {
[imageview removeFromSuperview];
}];
}
遍历集合数据类型中的每个元素
stop是BOOL *类型, 表示的是指向BOOL类型值的指针
[touches enumerateObjectsUsingBlock:^(UITouch *obj, BOOL* stop) {
// 每一次Block的执行, 都是集合中某一个元素的遍历操作
NSLog(@"helloWord: %@", obj);
// 当你找到需要的那个对象时, stop可以让遍历操作停下来
// 将stop所指向的那个BOOL类型的值改成YES
* stop = YES;
}];
}
控件不响应的情况
- 控件的用户交互被关闭, 无法响应事件
- setUserInteractionEnabled
- 如果父视图不能响应事件, 子控件也不能响应事件
- 响应者链条在父控件上断开
- 控件看不见时, 不能响应事件
- 被隐藏, hidden
- 透明度太小, <=0.01 (太透明, 跟没有一样)
- 触摸的点不在控件的有限范围之内
- 子控件如果超出了父控件的范围, 那部分就不属于子控件的有限范围
- 当超出部分没有被裁剪时, 会看得到超出的那部分范围, 但是它不会响应事件
超出父控件部分要裁剪
self.view.clipsToBounds = YES;
多点触摸:
- 视图默认支持1个点, 要启用多点支持, 额外配置
[self.view setMultipleTouchEnabled:YES];
- 集合的遍历, anyObject是任意的一个对象
- 取出全部的集合对象 allObjects
- 使用block遍历的方式 (数组, 字典, 集合)
** 响应事件触发时的调用堆栈**
- 运行循环 (检测整个应用的触摸事件) (死循环)
- 向UIApplication发送消息
- UIApplication向UIWindow (keyWindow)发送消息
- 依据响应者链条, 递归的让所有子视图都检测 (找出最终响应该事件的控件)
- 如果找到了, 最终会传递回UIApplication, 再来执行相关的事件调用
- 如果找不到, 最终也会传递回UIApplication, 由于没有控件能响应, 本次触摸结束
** 响应者链条**
- UIWindow 向下级传递, window的根控制器, 它的根视图
- 如果下级视图, 是某个控制器的根视图, 会先传递给控制器, 再由控制器传递给根视图
- 视图会先检查其子视图是否能够响应事件
- 每个视图, 都会优先检查子视图是否能响应
- 检查完所有子视图, 再检查
使用hitTest方法来进行链条的传递
- hitTest的返回值
- null本次的传递当中, 没有发现对应的控件
- UIView实例, 意味着找到响应的控件, 逆着链条将结果传递回去
- pointInside: withEvent:
传递响应连接的关键方法
返回值:
- 如果没有在响应范围之内, 是null
- 如果是当前视图的响应, 返回自己
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *view = [super hitTest:point withEvent:event];
NSLog(@"红色视图 - : %@", view);
return view;
};
该方法判断触摸点是否在本控件有限范围之内, 返回结果
hitTest默认是使用pointInSide来检测触摸点是否为本控件来响应
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL result = [super pointInside:point withEvent:event];
NSLog(@"%@", result ? @"触摸点在红色控件的范围之内" : @"不在范围内");
return result;
};
手势
UIImageView的坑点
UIImageView默认不支持用户交互, 手势不能用(触摸事件)
SB中有配置用户交互的选项
UIImageView在SB中当中, 是不给添加子视图
** UIGestureRecognizer 是所有具体手势的抽象类**
手势在SB|Xib当中都提供了对应的控件
可以拖拽使用, 手势是针对控件而言, 往哪个控件身上拖拽, 就是向哪个控件添加手势
可以直接在SB当中, 为手势添加对应的响应事件
一个控件是可以同时添加多个手势, 各自响应自己的事件
- 可以将两个手势同时添加到一个控件里
- 控件可以响应两个手势, 单独响应
- 允许两个手势同时响应 (默认不能允许)
- 在一次触摸事件的过程当中, 两个手势是可以同时来响应
- 通过UIGestureRecognizerDelegate方法来帮助实现
以下是部分手势添加示例 但是要手势有反应 需要实现方法(为手势添加方法)
捏合手势
Pinch 捏合手势 (放大缩小) UIPinchGestureRecognizer
- 实例化手势, 绑定触发的事件
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureAction:)];
pinchGesture.delegate = self;
- 将手势添加到某个视图当中
[self.imageView addGestureRecognizer:pinchGesture];
撮合手势的响应事件件(就是添加的方法 上面只是添加了手势 但是手势之后会怎样响应需要自行实现)
需要两个触摸点, 多点触摸的支持 (视图默认只支持一个点)
如果不能使用, 就打开多点触摸的配置
** 该响应事件会触发多次, (多个阶段)**
-(void)pinchGestureAction:(UIPinchGestureRecognizer *)sender
{
// scale 缩放比例 (两个点之间的距离变化)
NSLog(@"%f, %zd", sender.scale, sender.numberOfTouches);
// -------- 让图片跟随捏合进行放大缩小 --------
// 1. 获取到缩放值
// 2. 利用Transform来进行放大缩小
self.imageView.transform = CGAffineTransformScale(sender.view.transform, sender.scale, sender.scale);
// 重围scale初始计算值
sender.scale = 1.0;
}
旋转手势
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGestureAction:)];
rotationGesture.delegate = self;
[self.imageView addGestureRecognizer:rotationGesture];
旋转手势的响应事件(就是添加的方法 上面只是添加了手势 但是手势之后会怎样响应需要自行实现)
- (void)rotationGestureAction:(UIRotationGestureRecognizer *)sender
{
// 旋转的值的大小, 是弧度值
NSLog(@"%f", sender.rotation);
// 应用旋转
sender.view.transform = CGAffineTransformRotate(sender.view.transform, sender.rotation);
// 重置旋转的值的初始计算
sender.rotation = 0;
}
如果需要同时响应多个手势事件 需要实现以下方法 并遵守UIGestureRecognizerDelegate协议
返回是否允许多个手势识别器同时识别各自的事件
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
网友评论