【问题标题】:UIScrollView with touchesMoved not called未调用带有 touchesMoved 的 UIScrollView
【发布时间】:2012-08-28 20:22:13
【问题描述】:

我有一个包含 UIImageView 的 UIScrollView。 UIScrollView 允许在 UIImageView 中进行缩放和平移。

问题是我每次都想知道手指的移动,我试图用 touchesMoved 方法捕捉事件。 但它不起作用,尽管正确调用了 touchesBegan 和 touchesEnded。

实际上,如果手指移动非常小,并且 UIScrollView 没有开始平移,就会调用 touchesMoved。在 UIScrollView 开始移动的那一刻,事件停止被调用。

有人知道问题出在哪里以及如何解决吗? 我想也许里面的 UIImageView 正在捕捉事件或类似的东西。

【问题讨论】:

    标签: objective-c ios uiscrollview zooming panning


    【解决方案1】:

    实际上,这确实是一个相当大的问题,因为 UIScrollView 确实 "eat" TouchesMoved 事件(即使传播了几个第一个事件)。

    所以,我刚刚提出了直接从 UIWindow 获取事件的方法。这肯定不是应用程序结构意义上的最佳方法,但在某些自定义情况下(这正是我所需要的)很好。

    (示例在 MonoTouch C# 中)。

    创建您的 自定义 UIWindow(由于我的自定义逻辑(使用 MvvmCross 框架),我没有在这里展示如何用 MyWindow 替换标准 UIWindow,但这很容易,通常在 appDelegate 初始化逻辑中完成- 你会在 google/stack 溢出中发现):

    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),所以另外,如果你愿意,你可以取消窗口的事件传播,只有当你想阻止除你的之外的任何其他处理程序应用时(你例如,可以向您的处理程序添加“已处理”标志)。

    【讨论】:

      【解决方案2】:

      滚动视图属性canCancelContentTouches = NO 允许将触摸事件向上传递到响应者链。

      【讨论】:

        【解决方案3】:

        尝试使用 UIScrollViewDelegate 来跟踪偏移量变化或缩放比例变化。

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

        或者查看UIScrollViewtouchesBegan: & (touchesMoved: or touchesCancelled:) events之间的zoomScale值变化。

        【讨论】:

          【解决方案4】:

          创建一个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];
              }
          }
          

          【讨论】:

          • 我当然做到了。所以我是说 touchesMoved 没有被正确调用。
          • 尝试在滚动视图中关闭 delaysContentTouches。这将立即将所有子触摸直接转发到子视图,而不检查它是否是“滚动触摸”。
          • 没有区别。 delaysContentTouches=YES 或 NO,滚动视图的行为是一样的。
          【解决方案5】:

          请勾选此项以使用滚动视图的平移手势识别触摸事件(开始、移动、结束),

          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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多