UIScrollView с touchMoved не вызывается

У меня есть UIScrollView, содержащий UIImageView. UIScrollView позволяет масштабировать и панорамировать UIImageView.

Проблема в том, что я хотел бы знать движение пальца каждый раз, и я пытаюсь поймать событие с помощью метода touchesMoved. Но это не работает, несмотря на то, что touchesBegan и touchesEnded вызываются правильно.

Фактически, touchMoved вызывается, если движение пальца действительно небольшое, а UIScrollView не начинает панорамирование. В тот момент, когда UIScrollView начинает перемещаться, событие перестает вызываться.

Кто-нибудь знает в чем проблема и как исправить? Я подумал, что, возможно, UIImageView внутри улавливает событие или что-то в этом роде.


person user1573607    schedule 04.09.2012    source источник


Ответы (5)


На самом деле, это действительно серьезная проблема, поскольку UIScrollView "ест" TouchesMoved события (даже если распространяет несколько первых).

Итак, я только что придумал способ получать события непосредственно из UIWindow. Это, конечно, не лучший подход с точки зрения структуры приложения, но в некоторых нестандартных ситуациях (что было именно то, что мне было нужно) это нормально.

(Примеры приведены на MonoTouch C #).

Создайте свой настраиваемый UIWindow (я не показываю здесь, как заменить стандартный UIWindow на MyWindow из-за моей настраиваемой логики (с использованием структуры MvvmCross), но это довольно просто и обычно выполняется в логике инициализации appDelegate - вы будете найдите это в Google / stack overflow):

public class MyWindow : UIWindow
{
    public MyWindow(RectangleF bounds) : base(bounds)
    {

    }

    public override void SendEvent(UIEvent evt)
    {
        if (evt.Type == UIEventType.Touches) {
            var el = (UITouch)evt.AllTouches.AnyObject;

            if (el.Phase == UITouchPhase.Began)
            {
                if(OnTouchBegan != null)
                    OnTouchBegan(el.View, new TouchCommandArgs(evt.AllTouches, evt));
            }

            if (el.Phase == UITouchPhase.Moved)
            {
                if(OnTouchMoved != null)
                    OnTouchMoved(el.View, new TouchCommandArgs(evt.AllTouches, evt));
            }

            if (el.Phase == UITouchPhase.Ended)
            {
                if(OnTouchEnd != null)
                    OnTouchEnd(el.View, new TouchCommandArgs(evt.AllTouches, evt));
            }

            if (el.Phase == UITouchPhase.Cancelled)
            {
                if(OnTouchCancel != null)
                    OnTouchCancel(el.View, new TouchCommandArgs(evt.AllTouches, evt));
            }

        } else
            MvxTrace.Trace (evt.Type == null ?  "-" : evt.ToString ());
        base.SendEvent(evt);
    }

    public event TouchCommand OnTouchBegan;
    public event TouchCommand OnTouchEnd;
    public event TouchCommand OnTouchCancel;
    public event TouchCommand OnTouchMoved;

}

public class TouchCommandArgs : EventArgs
{
    public NSSet Touches { get; set; }
    public UIEvent Evt { get; set; }

    public TouchCommandArgs(NSSet touches, UIEvent evt)
    {
        Touches = touches;
        Evt = evt;
    }
}

а в месте обработки событий подпишитесь на пользовательские обработчики событий:

var window = (MyWindow) UIApplication.SharedApplication.KeyWindow;
window.OnTouchBegan += view_OnTouchBegan;
window.OnTouchMoved += view_OnTouchMoved;
window.OnTouchCancel += view_OnTouchCancel;
window.OnTouchEnd += view_OnTouchEnd;

такие обработчики, как (это все ваше собственное):

void view_OnTouchBegan(object sender, TouchCommandArgs args)
{
    // do your logic
}

В этом случае события будут обрабатываться одновременно (в обоих местах: в вашем и в UIScrollView), поэтому дополнительно, если вы хотите, вы можете отменить распространение событий окна, только если вы хотите предотвратить применение любых других обработчиков, кроме вашего (вы можете добавить " Например, обработанный флаг для ваших обработчиков).

person Agat    schedule 01.08.2013

Попробуйте использовать UIScrollViewDelegate, чтобы отследить изменение смещения или изменения масштаба.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (void)scrollViewDidZoom:(UIScrollView *)scrollView;

Или проверьте изменение значения zoomScale UIScrollView между touchesBegan: & (touchesMoved: or touchesCancelled:) events.

person JerryZhou    schedule 20.01.2014

Создайте подкласс класса UIScrollView и переопределите touchesBegan: и другие методы касания следующим образом:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // If not dragging, send event to next responder
    if (!self.dragging)
    { 
        [self.nextResponder touchesBegan: touches withEvent:event]; 
    }
    else
    {
        [super touchesEnded: touches withEvent: event];
    }
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // If not dragging, send event to next responder
    if(!self.dragging)
    { 
        [self.nextResponder touchesBegan: touches withEvent:event]; 
    }
    else
    {
        [super touchesEnded: touches withEvent: event];
    }
 }

 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // If not dragging, send event to next responder
    if (!self.dragging)
    { 
        [self.nextResponder touchesBegan: touches withEvent:event]; 
    }
    else
    {
        [super touchesEnded: touches withEvent: event];
    }
}
person prashant    schedule 04.09.2012
comment
Конечно, я это сделал. Итак, я говорю, что touchMoved не вызывается должным образом. - person user1573607; 04.09.2012
comment
Попробуйте отключить delaysContentTouches в режиме прокрутки. Это немедленно переадресует все дочерние касания непосредственно дочерним представлениям, не проверяя, является ли это «касанием прокрутки». - person prashant; 04.09.2012
comment
Нет никакой разницы. delaysContentTouches = YES или NO, поведение прокрутки такое же. - person user1573607; 04.09.2012

Свойство scrollview canCancelContentTouches = NO позволяет передавать события касания по цепочке респондента.

person Electro-Bunny    schedule 14.11.2012

Установите этот флажок, чтобы распознавать события касания (начало, перемещение, окончание) с помощью жеста панорамирования в режиме прокрутки,

Class CustomScrollView:UIScrollView
{

CustomScrollView()
{

 (this.GestureRecognizers[1] as UIPanGestureRecognizer).AddTarget(() => this.PanHandle(this.GestureRecognizers[1] as UIPanGestureRecognizer));
    

}


 private void PanHandle(UIPanGestureRecognizer gestureRecognizer)
          
  {
  var touchLocation=gestureRecognizer.LocationInView(this)
    
       

  if (gestureRecognizer.State == UIGestureRecognizerState.Began)
            
    {
             
      //Touches began
             
   }
     
else if (gestureRecognizer.State == UIGestureRecognizerState.Changed)
            
   {
           
        //Touches Moved
             
   }
               
 else if (gestureRecognizer.State == UIGestureRecognizerState.Ended)
         
       {
             
       //Touches ended
              
  }
           
 }

    }

Regards,
Ashwin
person Ashwin Kmr    schedule 11.10.2018