有些手勢其實是互相關連的,例如 Tap 與 LongPress、Swipe 與 Pan,或是 Tap 一次與 Tap 兩次。當一個 UIView 同時掛上兩個相關連的手勢時,到底我這一下手指頭按的要算是 Tap 還是 LongPress?如果照預設作法來看,只要「先滿足條件」的就會跳出並呼叫對應方法,舉例來說,如果同時註冊了 Pan 跟 Swipe,只要手指頭一移動就會觸發 Pan 然後跳出,因而永遠都不會發生 Swipe;單點與雙點的情形也是一樣,永遠都只會觸發單點,不會有雙點。
那麼這問題有解嗎?有的, UIGestureRecognizer 有個方法叫做 requireGestureRecognizerToFail ,他可以指定某一個 recognizer,即便自己已經滿足條件了,也不會立刻觸發,會等到該指定的 recognizer 確定失敗之後才觸發。以同時支援單點擊與雙點擊的作法為例,程式碼如下:
那麼這問題有解嗎?有的, UIGestureRecognizer 有個方法叫做 requireGestureRecognizerToFail ,他可以指定某一個 recognizer,即便自己已經滿足條件了,也不會立刻觸發,會等到該指定的 recognizer 確定失敗之後才觸發。以同時支援單點擊與雙點擊的作法為例,程式碼如下:
-
(
void
)
viewDidLoad
{
// 單擊的 Recognizer
UITapGestureRecognizer
*
singleRecognizer
;
singleRecognizer
=
[[
UITapGestureRecognizer
alloc
]
initWithTarget:
self
action:
@selector
(
handleSingleTapFrom
)];
singleTapRecognizer
.
numberOfTapsRequired
=
1
;
// 單擊
[
self
.
view
addGestureRecognizer:
singleRecognizer
];
// 雙擊的 Recognizer
UITapGestureRecognizer
*
double
;
doubleRecognizer
=
[[
UITapGestureRecognizer
alloc
]
initWithTarget:
self
action:
@selector
(
handleDoubleTapFrom
)];
doubleTapRecognizer
.
numberOfTapsRequired
=
2
;
// 雙擊
[
self
.
view
addGestureRecognizer:
doubleRecognizer
];
// 關鍵在這一行,如果雙擊確定偵測失敗才會觸發單擊
[
singleRecognizer
requireGestureRecognizerToFail:
doubleRecognizer
];
[
singleRecognizer
release
];
[
doubleRecognizer
release
];
}
- UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];
- [self.view addGestureRecognizer:panRecognizer];
- panRecognizer.maximumNumberOfTouches = 1;
- panRecognizer.delegate = self;
- [panRecognizer release];
第一个很简单,就是确定要给这个recognizer handle的event,就会去call这个class底下的handlePanFrom:
然后把recognizer加进UIView里(addGestureRecognizer),
因为同时间我只想知道一只手指的动作,所以我用maximumNumberOfTouches=1来限制,
当然,你可以改变maximumNumberOfTouches跟minimumNumberOfTouches的值来当成filter,接着把delegate设定成自己(记得header要加上UIGestureRecognizerDelegate),不过这样还没有结束...
我们要补上这个delegate method
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
- }
里面可以先filter event,决定要不要丢给一开始assign给panRecognizer的selector function
譬如我只想要看某个subview的事件
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
- UIView *aview = [self.view viewWithTag:1000];
- if (touch.view != aview) {
- return NO; // 不理這個event
- }
- return YES;
- }
接下来就是
- - (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
- //拿到手指目前的位置
- CGPoint location = [recognizer locationInView:self.view];
- UIView *aview = [self.view viewWithTag:1000];
-
- // 如果UIGestureRecognizerStateEnded的話...你是拿不到location的
- // 不判斷的話,底下改frame會讓這個subview消失,因為origin的x和y就不見了!!!
- if(recognizer.state != UIGestureRecognizerStateEnded)
- {
- aview.frame = CGRectMake(location.x, location.y, aview.frame.size.width, aview.frame.size.height);
- }
- }
不同的UIGestureRecognizer subclass都会有不同特点,譬如说Pinch的scale,velocity和Swipe的direction,
直接简化了处理UITouch的步骤,大家只要知道这些特点,处理使用者输入就会得心应手啦~
遇到灵异事件...记得先看看有没有判断UIGestureRecognizer的state