UIScrollView with touchesMoved not called

2019-02-26 10:56发布

I've a UIScrollView that contains an UIImageView. The UIScrollView lets zooming and panning through the UIImageView.

The problem is that I would like know the finger movement every time, and I'm trying to catch the event with touchesMoved method. But it's not working, despite touchesBegan and touchesEnded that are called correctly.

In fact, touchesMoved is called if the finger movement is really small, and the UIScrollView doesn't started panning. At the moment that UIScrollView starts getting moved, the event stops being called.

Somebody know what's the problem and how to fix it? I've thought that maybe the UIImageView inside is catching the event or something like that.

5条回答
霸刀☆藐视天下
2楼-- · 2019-02-26 11:18

Try to use the UIScrollViewDelegate to trace the offset change or zoom scale changes.

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

Or check the zoomScale value change of UIScrollView between touchesBegan: & (touchesMoved: or touchesCancelled:) events.

查看更多
戒情不戒烟
3楼-- · 2019-02-26 11:22

Create a subclass of UIScrollView class and override the touchesBegan: and other touch methods as follows:

-(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];
    }
}
查看更多
放我归山
4楼-- · 2019-02-26 11:24

Please check this to recognize touch events(began,moved,ended) using pan gesture of the scrollview,

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
查看更多
Anthone
5楼-- · 2019-02-26 11:41

Actually, that's really quite a problem, as the UIScrollView does "eat" TouchesMoved events (even if propagates several first ones).

So, I've just come up with the approach to get the events directly from UIWindow. That's for sure not the best approach in the application structure sense, but in some custom situation (which was exactly what I needed) is fine.

(Examples are in MonoTouch C#).

Create your custom UIWindow (I don't show here how to replace standard UIWindow with MyWindow due to my custom logic (using MvvmCross framework), but that's pretty easy and usually done in appDelegate initialization logic - you will find that in 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;
    }
}

and in the place to handle the events subscribe for the custom events handlers:

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

handlers like (that's all by your own):

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

In that case the events will be handling simultaneously (in both places: yours and UIScrollView), so additionally if you want, you can cancel the window's event propagation only if you want to prevent any other handlers to apply except yours (you can add "Handled" flag to your handlers, for instance).

查看更多
\"骚年 ilove
6楼-- · 2019-02-26 11:43

The scrollview property canCancelContentTouches = NO allows the touch events to be passed up the responder chain.

查看更多
登录 后发表回答