2013年2月4日 星期一

可愛的讓我面紅的可愛兔子 - 手勢偵測的陷阱

透過iOS SDK內建的手勢物件,我們可以輕易判斷一些常見的手勢,諸如tab,swipe之類,然而,在iOS 5之前的舊系統(包含iOS 5),學會了判斷手勢的神功,卻會帶給我們意想不到的副作用。接下來彼得潘將以好朋友彼得兔做例子,讓我們瞧瞧手勢物件在iOS 5裡做的好事! 

1. 在畫面上加上tap手勢的偵測以及彼得兔button

- (void)viewDidLoad

{

    [superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    

    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(tap:)];

    [self.viewaddGestureRecognizer:tapGesture];

    
    UIButton *but = [[UIButtonalloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
    [self.viewaddSubview:but];
    but.contentMode = UIViewContentModeScaleAspectFit;
    [but setImage:[UIImageimageNamed:@"rabbit.jpg"] forState:UIControlStateNormal];
    [but addTarget:selfaction:@selector(showCuteRabbit:) forControlEvents:UIControlEventTouchUpInside];

}
說明:
(1)  UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(tap:)];

建立偵測tap手勢的UITapGestureRecognizer物件。當偵測到tap動作時,tap: method將被呼叫。


(2)     [but addTarget:selfaction:@selector(showCuteRabbit:) forControlEvents:UIControlEventTouchUpInside];

當點選彼得兔button時,showCuteRabbit: method將被呼叫

2. 定義點選彼得兔button時,執行的showCuteRabbit: method

-(void)showCuteRabbit:(id)sender

{

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"可愛的讓我面紅的可愛兔子" message:nil delegate:nil cancelButtonTitle:@"Ok"otherButtonTitles:nil];

    [alertView show];

}
說明:
彼得兔是如此可愛,讓我們稍微改一下周杰倫可愛女人的歌詞,顯示"可愛的讓我面紅的可愛兔子"吧

3. 定義偵測到tap動作時,執行的tap: method

-(void)tap:(id)sender

{

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"漂亮的讓我面紅的可愛女人" message:nil delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];

    [alertView show];

}
說明:
為了讓原版歌詞露臉,當tap: method執行時,我們顯示原來的歌詞"漂亮的讓我面紅的可愛女人"。

執行App:


在iOS 6時一切正常,點選彼得兔時顯示”可愛兔子”,點選其它地方時顯示”可愛女人"


切到iOS 5時,一切卻都變了樣。當我們點選彼得兔時,依然顯示”可愛女人”,這叫彼得兔情何以堪呢?尤其彼得兔還是個百分百的男兒身。



問題出在iOS 5時偵測tap的UITapGestureRecognizer物件會連點選button的動作也一併攔截,造成最後tap: method被執行,而沒有呼叫showCuteRabbit:。不過也不是無藥可救啦,只要將tap: method稍加修改,在iOS  5一樣可以判斷使用者真正點選的是button。




-(void)tap:(id)sender
{
    CGPoint point = [sender locationInView:but];  
    BOOL isPointInside = [but pointInside:point withEvent:nil];
    if(isPointInside)
    {
        [selfshowCuteRabbit:nil];
    }
    else
    {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"漂亮的讓我面紅的可愛女人" message:nil delegate:nil
                                                  cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alertView show];

    }
   
}
說明:
(1)     CGPoint point = [sender locationInView:but];    

取得使用者點選的座標位置。注意,我們傳入locationInView: method的參數是代表彼得兔的UIButton物件but (注意but也要宣告為view controller的member,而不能是local變數),所以此時取得的座標位置將是相對於彼得兔按鈕的座標位置,也就是當我們點選按鈕左邊,不屬於按鈕的區塊時,取得的x座標將是負的。

(2)     BOOL isPointInside = [but pointInside:point withEvent:nil];

判斷點選的座標位置是否位在彼得兔按鈕but裡。

(3)   if(isPointInside)
    {
        [self showCuteRabbit:nil];
    }

如果點選的座標位置在彼得兔按鈕裡,即表示使用者點選的是彼得兔,應該呼叫showCuteRabbit: method,否則了話則維持原狀,顯示"可愛女人"







沒有留言:

張貼留言