3

UIPanGesture サブクラスは次のとおりです。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"touches began");
   self ->origLoc = [[touches anyObject] locationInView:self.view.superview];
   [super touchesBegan:touches withEvent:event];
}


- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.state == UIGestureRecognizerStatePossible) {
    CGPoint loc = [[touches anyObject] locationInView:self.view.superview];
    CGFloat deltaX = fabsf(loc.x - origLoc.x);
    CGFloat deltaY = fabsf(loc.y - origLoc.y);
    if (deltaY >= deltaX) {
        self.state = UIGestureRecognizerStateFailed;
    } else {
    [super touchesMoved:touches withEvent:event];
    }
}
}

- (CGPoint) translationInView:(UIView *)v {

CGPoint proposedTranslation = [super translationInView:v];
proposedTranslation.y = 0;
return proposedTranslation;

}

サブクラス化された UIPanGesture によって呼び出されるメソッドは次のとおりです。

- (void)dragging: (UIPanGestureRecognizer *)p {    

UIView *vv = p.view;

if (p.state == UIGestureRecognizerStateBegan || p.state == UIGestureRecognizerStateChanged) {
    CGPoint delta = [p translationInView:vv.superview];
    CGPoint c = vv.center;
    c.x += delta.x;
    c.y += delta.y;
    vv.center = c;
    [p setTranslation:CGPointZero inView:vv.superview];
 }    
}

ビューをドラッグしようとすると、ごくわずかに移動してから停止します。それを動かすために、私はそれを少しずつ動かし続ける必要があります。何か案は?

前もって感謝します、

マイケル。

4

3 に答える 3

2

以前のコメントでは、なぜサブクラス化したのかは明確ではありませんでしたが、複数のジェスチャハンドラーが実行されているためです。とても良い。

したがって、カスタムパンジェスチャのサンプルコードHorizo​​ntalPanGestureRecognizerを次に示します。これは、最初の動きが水平の場合にのみトリガーされます。

// HorizontalPanGestureRecognizer.h

#import <UIKit/UIKit.h>

@interface HorizontalPanGestureRecognizer : UIPanGestureRecognizer
@end

// HorizontalPanGestureRecognizer.m

#import "HorizontalPanGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>

@interface HorizontalPanGestureRecognizer ()
{
    BOOL _hasConfirmedDirection;
    BOOL _wasHorizontal;
    CGPoint _origLoc;
}
@end

@implementation HorizontalPanGestureRecognizer

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];

    UITouch *touch = [touches anyObject];

    _hasConfirmedDirection = NO;

    _origLoc = [touch locationInView:self.view];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    if (self.state == UIGestureRecognizerStateFailed) return;

    if (!_hasConfirmedDirection)
    {
        CGPoint translation = [self translationInView:self.view];

        _hasConfirmedDirection = YES;
        _wasHorizontal = (fabs(translation.x) > fabs(translation.y));
    }
    if (!_wasHorizontal)
        self.state = UIGestureRecognizerStateFailed;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];

    if (!_wasHorizontal)
        self.state = UIGestureRecognizerStateFailed;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];

    if (!_wasHorizontal)
        self.state = UIGestureRecognizerStateFailed;
}

- (CGPoint)locationInView:(UIView *)view
{
    CGPoint superLocation = [super locationInView:view];

    if (_hasConfirmedDirection)
        superLocation.y = _origLoc.y;

    return superLocation;
}

- (CGPoint)translationInView:(UIView *)view
{
    CGPoint superTranslation = [super translationInView:view];

    if (_hasConfirmedDirection)
        superTranslation.y = 0.0f;

    return superTranslation;
}

@end

次に、メインビューコントローラーのハンドラーに適切に使用させることができます(この例では、UILabelをドラッグするだけです)。viewDidLoadで、ジェスチャを作成します。

HorizontalPanGestureRecognizer *recognizer = [[HorizontalPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleCustomPan:)];
[self.view addGestureRecognizer:recognizer];

そして、ハンドラーは次のようになります。

- (void)handleCustomPan:(UIPanGestureRecognizer *)sender 
{    
    switch (sender.state) {
        case UIGestureRecognizerStateChanged:
            if (!_panLabel)
            {
                // In my case I'm creating a UILabel to drag around, whereas you might just drag
                // whatever countrol you want to drag.
                //
                // But, regardless, I'm keeping track of the original center in _panLabelOrigCenter

                [self makePanLabel:sender]; 
            }

            CGPoint translate = [sender translationInView:self.view];
            _panLabel.center = CGPointMake(_panLabelOrigCenter.x + translate.x, _panLabelOrigCenter.y + translate.y);

            break;

        case UIGestureRecognizerStateEnded:
            [self removePanLabel];
            break;

        default:
            break;
    }
}

(明らかに、これはARCコードです。ARC以外の場合は、ルーチンのメモリ管理に必要なコード行を追加してください。)

于 2012-06-15T01:11:10.473 に答える
0

タッチが動いたときのその失敗状態は、初期の動きに非常に敏感になるようです。

感度を下げることを検討してください...

- (BOOL)movementIsHorizontalX:(CGFloat)x andY:(CGFloat) y {

    CGFloat absX = fabs(x);
    CGFloat absY = fabs(y);

    // if x is small, then accept small y values but not large ones
    if (absX < 4) return absY < 4;

    // now we can express horizontal-ness as a slope.  we've ruled out small x, so this is a stable calculation
    CGFloat slope = absY / absX;
    return slope < 0.10;

    // you could generalize by passing in the x threshold and percentage slope constants
}
于 2012-06-13T06:27:22.773 に答える
0

私は自分の間違いに気づきました。引っ越した

    [super touchesMoved: touches withEvent:event];  

if ステートメントの外側で、今では正常に動作しているようです。なぜ今それが機能するのかは 100% 確実ではありませんが、機能していることを嬉しく思います。

これがキャンセル/失敗するまで、UIScrollViewがパンジェスチャを受け入れないようにする方法を理解するために...

于 2012-06-13T19:29:13.303 に答える