UIButton Touch拖动/退出命中区域的大小是多少?

时间:2013-04-30 18:45:15

标签: ios cocoa-touch button uibutton touch

嗯,我想最好表明我的意思:

Animation of a UIButton reacting to dragging motions

您可以清楚地看到,一旦我们触摸按钮并移出按钮,随后的移入事件会触发从远处按钮状态的变化。

虽然这种行为对于所有UIButton都很自然,但我无法谷歌解决方案来改变它。

有没有办法减少此类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];
}

它改变了Drag In / Drag Out事件使用的命中区域扩展,但按钮Up / Down状态切换方式与之前完全相同。

2 个答案:

答案 0 :(得分:2)

Swift版本:

  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)
    }
  }

答案 1 :(得分:1)

我不知道你是否还有同样的问题,但我可以通过在touchesEnded:withEvent:方法中使用类似的代码来修复它。

我还改变了添加touchEnter和dragInside的方法,因为使用当前代码,那些事件仍使用相同的边界。另外我让每个案例都返回YES,这样就不会调用super(这会导致内部的触摸拖动被过早调用)。

以下是我最终得到的最终代码,有两种方法:

- (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];
}

注意:没有必要在最后返回方法的超级,但我把它留在那里是为了完整。