受け入れられた回答には2つの問題があることがわかりました。
- 登録されたアクションは 2 回呼び出されます:
- 1 回目は、上書きされた方法で設定されている 25 ピクセルのコントロールから指が離れたときです。
- 2 回目は、指がコントロールから約 70 ピクセル離れたときに呼び出されます。これは、UIControl のデフォルトの動作です。
event
2 番目の問題は、パラメータから取得した位置が であり(0, 0)
、正しく初期化されていないことです。
この回答に基づいて、この目的を達成する別の方法を見つけました。基本的な考え方は、そのメソッドを上書きするのではなく、コールバックでイベントを処理することです。次の 2 つの手順があります。
アクションを登録します。
// to get the touch up event
[btn addTarget:self action:@selector(btnTouchUp:withEvent:) forControlEvents:UIControlEventTouchUpInside];
[btn addTarget:self action:@selector(btnTouchUp:withEvent:) forControlEvents:UIControlEventTouchUpOutside];
// to get the drag event
[btn addTarget:self action:@selector(btnDragged:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[btn addTarget:self action:@selector(btnDragged:withEvent:) forControlEvents:UIControlEventTouchDragOutside];
イベントを処理します。
- (void)btnTouchUp:(UIButton *)sender withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGFloat boundsExtension = 25.0f;
CGRect outerBounds = CGRectInset(sender.bounds, -1 * boundsExtension, -1 * boundsExtension);
BOOL touchOutside = !CGRectContainsPoint(outerBounds, [touch locationInView:sender]);
if (touchOutside) {
// UIControlEventTouchUpOutside
} else {
// UIControlEventTouchUpInside
}
}
- (void)btnDragged:(UIButton *)sender withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGFloat boundsExtension = 25.0f;
CGRect outerBounds = CGRectInset(sender.bounds, -1 * boundsExtension, -1 * boundsExtension);
BOOL touchOutside = !CGRectContainsPoint(outerBounds, [touch locationInView:sender]);
if (touchOutside) {
BOOL previewTouchInside = CGRectContainsPoint(outerBounds, [touch previousLocationInView:sender]);
if (previewTouchInside) {
// UIControlEventTouchDragExit
} else {
// UIControlEventTouchDragOutside
}
} else {
BOOL previewTouchOutside = !CGRectContainsPoint(outerBounds, [touch previousLocationInView:sender]);
if (previewTouchOutside) {
// UIControlEventTouchDragEnter
} else {
// UIControlEventTouchDragInside
}
}
}
これで、6 つのイベントすべてを25
ピクセルの境界拡張で処理できるようになりました。もちろん、この値を必要に応じて他の値に設定することもできます。