2012-06-13 1 views
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]; 
}  
} 

Когда я пытаюсь перетащить мой взгляд вокруг, она просто перемещает очень небольшое количество и затем останавливается. Мне нужно продолжать подталкивать его, чтобы заставить его двигаться. Есть идеи?

Заранее благодарен,

Michael.

+0

danh, вероятно, идет по правильной линии мысли. Из любопытства, что вы пытаетесь сделать с этим подклассом распознавания жеста? Если вы просто пытаетесь повернуть влево и вправо, есть более простые способы решить эту проблему. Или у вас есть другой распознаватель жестов, обрабатывающий вертикальное движение, и вы пытаетесь определить, какой распознаватель жестов использовать? Но я бы подумал, что после того, как вы закроетесь в определенном распознавателе, вы прекратите дальнейшую проверку направления движения (чтобы допускать незначительные изменения от движения минутного пальца). – Rob

+0

Он действует на ячейку в GMGridView (UIScrollview), и я просто хочу, чтобы можно было панорамировать содержимое в пределах одной из ячеек влево или вправо, если обнаружено горизонтальное панорамирование, и прокручивать весь вид, если обнаружена вертикальная панорама , Вы говорите, что я должен перестать проверять направление движения, как я могу это сделать? –

+0

Нижняя строка, есть одна переменная, которая отслеживает, подтвердили ли вы, было ли вы проверено направление начального движения, а другое, указывающее, была ли она горизонтальной или нет. Затем вы можете просто проверить эту переменную, которая отслеживает, было ли начальное движение горизонтальным или не определять, измените ли вы состояние на UIGestureRecognizerStateFailed или нет. См. Мой ответ. – Rob

ответ

2

В моих предыдущих комментариях, я не ясно, почему вы были подклассов, но уточнить и это потому, что у вас много обработчиков жестов. Отлично.

Так вот некоторые примеры кода для пользовательского панорамирование жест, HorizontalPanGestureRecognizer, который срабатывает только тогда, когда первое движение по горизонтали:

// 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, добавить необходимые дополнительные линии. код для рутинного управления памятью.)

+0

Фантастическое спасибо! –

+0

Привет, Роб, я просто пытаюсь использовать выше, но получаю два erros 1. Нет видимого @interface для 'UIPanGestureRecognizer' объявляет селектор 'touchesEnded: withEvent:' 2. Присвоение свойства readonly. Вы можете использовать PLZ. –

+1

@PavanMore Вы должны использовать '#import ' (это заголовок, который будет использоваться при подклассе распознавателя жестов, выставляя некоторые частные методы, а также некоторые типичные свойства 'readonly' как' readwrite') , Извините, что это было неясно, и я попытался прояснить свой ответ. – Rob

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 
} 
+0

Да, это имеет смысл. Есть ли лучшее место для проверки? Я бы очень хотел, чтобы представление принимало только горизонтальное перемещение и предотвращало вертикальную прокрутку надзора (UIScrollView). Если свиток изначально вертикальный, чем свиток, можно прокручивать, а горизонтальное движение можно игнорировать. –

+0

Я думаю, что это хорошее место для проверки, но мы можем улучшить тест. См. Мое редактирование. – danh

+0

Спасибо за ваши ответы. Теперь у меня есть следующее: см. Ниже: –

0

я понял свою ошибку. Я переехал

[super touchesMoved: touches withEvent:event]; 

за пределами оператора if, и теперь он работает нормально. На самом деле не 100% уверены, почему это работает сейчас, но я счастлив, что это так.

Теперь, чтобы выяснить, как предотвратить UIScrollView от принятия жест панорамирования, пока этот не отменяет/терпит неудачу ...

+0

Код, включенный в мой ответ, обрабатывает панорамирование, если оно инициировано по горизонтали (и, таким образом, распознаватель жеста UITableView не получает его), но игнорирует его и передает его стандартным жестам tableview, распознанным при вертикальном запуске. Если я неправильно понял, что вы пытаетесь сделать, сообщите мне. – Rob

+0

Вот именно это, спасибо Роберту. –