2013-04-30 38 views
8

嗯,我想這是最好的說明我的意思:UIButton的Touch Drag/Exit命中區域的大小是怎樣的?

Animation of a UIButton reacting to dragging motions

你可以清楚地看到,一旦我們觸動按鈕,並搬出了它,隨之而來的舉動,在事件觸發按鈕狀態從遠處改變。

雖然這種行爲對於所有UIButtons來說都很自然,但我無法谷歌解決方案來改變它。

有沒有辦法減少這種類型的UIButton靈敏度的命中區域?我希望它減少了,因爲我覺得按鈕足夠大,它將提供更好的用戶體驗以及上/下音效。

UPD:爲UIButton的以下重寫代碼被張貼在another thread

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event 
{ 
    CGFloat boundsExtension = 25.0f; 
    CGRect outerBounds = CGRectInset(self.bounds, -1 * boundsExtension, -1 * boundsExtension); 

    BOOL touchOutside = !CGRectContainsPoint(outerBounds, [touch locationInView:self]); 
    if(touchOutside) 
    { 
     BOOL previousTouchInside = CGRectContainsPoint(outerBounds, [touch previousLocationInView:self]); 
     if(previousTouchInside) 
     { 
      NSLog(@"Sending UIControlEventTouchDragExit"); 
      [self sendActionsForControlEvents:UIControlEventTouchDragExit]; 
     } 
     else 
     { 
      NSLog(@"Sending UIControlEventTouchDragOutside"); 
      [self sendActionsForControlEvents:UIControlEventTouchDragOutside]; 
     } 
    } 
    return [super continueTrackingWithTouch:touch withEvent:event]; 
} 

它改變使用拖動/拖出事件的點擊區域擴展,但按鈕向上/向下狀態切換完全和以前一樣。

+1

似乎是這個問題的一個副本: http://stackoverflow.com/questions/14340122/uicontroleventtouchdragexit-triggers-when-100-pixels-away-從uibutton – 2013-04-30 18:51:43

+1

是的,差不多,但提供的答案不會改變按鈕的向上/向下狀態。他們似乎依靠100.0f命中區域擴展的其他東西。 – Kai 2013-04-30 19:01:29

回答

1

我不知道你是否仍然有同樣的問題,但我可以通過在touchesEnded:withEvent:方法中使用類似的代碼來解決它。

我也改變了這個方法來添加touchEnter和dragInside,因爲用當前的代碼,那些事件仍然使用相同的邊界。另外,我讓每個case都返回YES,這樣super就不會被調用(這會導致內部的touch過早被調用)。

這裏是最後的代碼,我結束了,有兩種方法:

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event 
{ 
    CGFloat boundsExtension = 25.0f; 
    CGRect outerBounds = CGRectInset(self.bounds, -1 * boundsExtension, -1 * boundsExtension); 

    BOOL touchOutside = !CGRectContainsPoint(outerBounds, [touch locationInView:self]); 
    if(touchOutside) { 
     BOOL previousTouchInside = CGRectContainsPoint(outerBounds, [touch previousLocationInView:self]); 
     if(previousTouchInside) { 
      [self sendActionsForControlEvents:UIControlEventTouchDragExit]; 
      return YES; 
     } 
     else 
     { 
      [self sendActionsForControlEvents:UIControlEventTouchDragOutside]; 
      return YES; 
     } 
    } 
    else { 
     BOOL previousTouchOutside = !CGRectContainsPoint(outerBounds, [touch previousLocationInView:self]); 
     if (previousTouchOutside) { 
      [self sendActionsForControlEvents:UIControlEventTouchDragEnter]; 
      return YES; 
     } 
     else { 
      [self sendActionsForControlEvents:UIControlEventTouchDragInside]; 
      return YES; 
     } 
    } 
    return [super continueTrackingWithTouch:touch withEvent:event]; 
} 


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *touch = [touches anyObject]; 
    CGFloat boundsExtension = 25.0f; 
    CGRect outerBounds = CGRectInset(self.bounds, -1 * boundsExtension, -1 * boundsExtension); 

    BOOL touchInside = CGRectContainsPoint(outerBounds, [touch locationInView:self]); 
    if (touchInside) { 
     return [self sendActionsForControlEvents:UIControlEventTouchUpInside]; 
    } 
    else { 
     return [self sendActionsForControlEvents:UIControlEventTouchUpOutside]; 
    } 
    return [super endTrackingWithTouch:touch withEvent:event]; 
} 

注:返回末尾的方法的超是沒有必要的,但我把它放在那裏的完整性。

2

迅速版本:

private let _boundsExtension: CGFloat = 0 // Adjust this as needed 

    override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool { 
    let outerBounds: CGRect = CGRectInset(bounds, -1 * _boundsExtension, -1 * _boundsExtension) 
    let currentLocation: CGPoint = touch.locationInView(self) 
    let previousLocation: CGPoint = touch.previousLocationInView(self) 

    let touchOutside: Bool = !CGRectContainsPoint(outerBounds, currentLocation) 
    if touchOutside { 
     let previousTouchInside: Bool = CGRectContainsPoint(outerBounds, previousLocation) 
     if previousTouchInside { 
     sendActionsForControlEvents(.TouchDragExit) 
     } else { 
     sendActionsForControlEvents(.TouchDragOutside) 
     } 
    } else { 
     let previousTouchOutside: Bool = !CGRectContainsPoint(outerBounds, previousLocation) 
     if previousTouchOutside { 
     sendActionsForControlEvents(.TouchDragEnter) 
     } else { 
     sendActionsForControlEvents(.TouchDragInside) 
     } 
    } 

    return true 
    } 

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { 
    let touch: UITouch = touches.first! 
    let outerBounds: CGRect = CGRectInset(bounds, -1 * _boundsExtension, -1 * _boundsExtension) 
    let currentLocation: CGPoint = touch.locationInView(self) 

    let touchInside: Bool = CGRectContainsPoint(outerBounds, currentLocation) 
    if touchInside { 
     return sendActionsForControlEvents(.TouchUpInside) 
    } else { 
     return sendActionsForControlEvents(.TouchUpOutside) 
    } 
    }