搖一搖的相關(guān)事件, 都是從UIResponder中繼承過來的
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
NSLog(@"開始搖一搖");
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
NSLog(@"結(jié)束搖一搖");
}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
// 如來電
NSLog(@"搖一搖被取消");
}
觸摸開始, 手指按下去 (沒有松開)
在一次手勢觸摸的過程(從按下到松開), 只執(zhí)行一次
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
觸摸后開始移動, 手指按下后還沒有松開, 然后開始移動 (手指還沒有離開屏幕)
在一次手勢觸摸的過程(從按下到松開), 會執(zhí)行很多次
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
觸摸結(jié)束, 手指離開了屏幕了
- (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];
示例:
以下方法實現(xiàn)后 添加視圖素材 可以實現(xiàn)觸摸屏幕的同時 觸摸的地方顯示素材光點
- (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];
}];
}
遍歷集合數(shù)據(jù)類型中的每個元素
stop是BOOL *類型, 表示的是指向BOOL類型值的指針
[touches enumerateObjectsUsingBlock:^(UITouch *obj, BOOL* stop) {
// 每一次Block的執(zhí)行, 都是集合中某一個元素的遍歷操作
NSLog(@"helloWord: %@", obj);
// 當你找到需要的那個對象時, stop可以讓遍歷操作停下來
// 將stop所指向的那個BOOL類型的值改成YES
* stop = YES;
}];
}
控件不響應(yīng)的情況
- 控件的用戶交互被關(guān)閉, 無法響應(yīng)事件
- setUserInteractionEnabled
- 如果父視圖不能響應(yīng)事件, 子控件也不能響應(yīng)事件
- 響應(yīng)者鏈條在父控件上斷開
- 控件看不見時, 不能響應(yīng)事件
- 被隱藏, hidden
- 透明度太小, <=0.01 (太透明, 跟沒有一樣)
- 觸摸的點不在控件的有限范圍之內(nèi)
- 子控件如果超出了父控件的范圍, 那部分就不屬于子控件的有限范圍
- 當超出部分沒有被裁剪時, 會看得到超出的那部分范圍, 但是它不會響應(yīng)事件
超出父控件部分要裁剪
self.view.clipsToBounds = YES;
多點觸摸:
- 視圖默認支持1個點, 要啟用多點支持, 額外配置
[self.view setMultipleTouchEnabled:YES];
- 集合的遍歷, anyObject是任意的一個對象
- 取出全部的集合對象 allObjects
- 使用block遍歷的方式 (數(shù)組, 字典, 集合)
** 響應(yīng)事件觸發(fā)時的調(diào)用堆棧**
- 運行循環(huán) (檢測整個應(yīng)用的觸摸事件) (死循環(huán))
- 向UIApplication發(fā)送消息
- UIApplication向UIWindow (keyWindow)發(fā)送消息
- 依據(jù)響應(yīng)者鏈條, 遞歸的讓所有子視圖都檢測 (找出最終響應(yīng)該事件的控件)
- 如果找到了, 最終會傳遞回UIApplication, 再來執(zhí)行相關(guān)的事件調(diào)用
- 如果找不到, 最終也會傳遞回UIApplication, 由于沒有控件能響應(yīng), 本次觸摸結(jié)束
** 響應(yīng)者鏈條**
- UIWindow 向下級傳遞, window的根控制器, 它的根視圖
- 如果下級視圖, 是某個控制器的根視圖, 會先傳遞給控制器, 再由控制器傳遞給根視圖
- 視圖會先檢查其子視圖是否能夠響應(yīng)事件
- 每個視圖, 都會優(yōu)先檢查子視圖是否能響應(yīng)
- 檢查完所有子視圖, 再檢查
使用hitTest方法來進行鏈條的傳遞
- hitTest的返回值
- null本次的傳遞當中, 沒有發(fā)現(xiàn)對應(yīng)的控件
- UIView實例, 意味著找到響應(yīng)的控件, 逆著鏈條將結(jié)果傳遞回去
- pointInside: withEvent:
傳遞響應(yīng)連接的關(guān)鍵方法
返回值:
- 如果沒有在響應(yīng)范圍之內(nèi), 是null
- 如果是當前視圖的響應(yīng), 返回自己
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *view = [super hitTest:point withEvent:event];
NSLog(@"紅色視圖 - : %@", view);
return view;
};
該方法判斷觸摸點是否在本控件有限范圍之內(nèi), 返回結(jié)果
hitTest默認是使用pointInSide來檢測觸摸點是否為本控件來響應(yīng)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL result = [super pointInside:point withEvent:event];
NSLog(@"%@", result ? @"觸摸點在紅色控件的范圍之內(nèi)" : @"不在范圍內(nèi)");
return result;
};
手勢
UIImageView的坑點
UIImageView默認不支持用戶交互, 手勢不能用(觸摸事件)
SB中有配置用戶交互的選項
UIImageView在SB中當中, 是不給添加子視圖
** UIGestureRecognizer 是所有具體手勢的抽象類**
手勢在SB|Xib當中都提供了對應(yīng)的控件
可以拖拽使用, 手勢是針對控件而言, 往哪個控件身上拖拽, 就是向哪個控件添加手勢
可以直接在SB當中, 為手勢添加對應(yīng)的響應(yīng)事件
一個控件是可以同時添加多個手勢, 各自響應(yīng)自己的事件
- 可以將兩個手勢同時添加到一個控件里
- 控件可以響應(yīng)兩個手勢, 單獨響應(yīng)
- 允許兩個手勢同時響應(yīng) (默認不能允許)
- 在一次觸摸事件的過程當中, 兩個手勢是可以同時來響應(yīng)
- 通過UIGestureRecognizerDelegate方法來幫助實現(xiàn)
以下是部分手勢添加示例 但是要手勢有反應(yīng) 需要實現(xiàn)方法(為手勢添加方法)
捏合手勢
Pinch 捏合手勢 (放大縮小) UIPinchGestureRecognizer
- 實例化手勢, 綁定觸發(fā)的事件
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureAction:)];
pinchGesture.delegate = self;
- 將手勢添加到某個視圖當中
[self.imageView addGestureRecognizer:pinchGesture];
撮合手勢的響應(yīng)事件件(就是添加的方法 上面只是添加了手勢 但是手勢之后會怎樣響應(yīng)需要自行實現(xiàn))
需要兩個觸摸點, 多點觸摸的支持 (視圖默認只支持一個點)
如果不能使用, 就打開多點觸摸的配置
** 該響應(yīng)事件會觸發(fā)多次, (多個階段)**
-(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;
}
旋轉(zhuǎn)手勢
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGestureAction:)];
rotationGesture.delegate = self;
[self.imageView addGestureRecognizer:rotationGesture];
旋轉(zhuǎn)手勢的響應(yīng)事件(就是添加的方法 上面只是添加了手勢 但是手勢之后會怎樣響應(yīng)需要自行實現(xiàn))
- (void)rotationGestureAction:(UIRotationGestureRecognizer *)sender
{
// 旋轉(zhuǎn)的值的大小, 是弧度值
NSLog(@"%f", sender.rotation);
// 應(yīng)用旋轉(zhuǎn)
sender.view.transform = CGAffineTransformRotate(sender.view.transform, sender.rotation);
// 重置旋轉(zhuǎn)的值的初始計算
sender.rotation = 0;
}
如果需要同時響應(yīng)多個手勢事件 需要實現(xiàn)以下方法 并遵守UIGestureRecognizerDelegate協(xié)議
返回是否允許多個手勢識別器同時識別各自的事件
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}