iPhone - 处理UIViewController中的触摸幻灯片

时间:2010-06-22 13:24:14

标签: iphone cocoa-touch uiviewcontroller uiscrollview

我想在UIViewController子类中处理触摸(特别是水平幻灯片),但问题是控制器的视图包含覆盖整个屏幕的UIScrollView,因此“touchesBegan:”和“touchesEnded:”事件永远不会在我的控制器中调用。滚动视图仅垂直滚动。

使它能够处理这些事件的最佳方法是什么?让我的UIViewController也继承UIScrollView并根据需要处理触摸(并删除当前的滚动视图),或使用UIScrollView子类代替我当前的滚动视图,它将调用我需要的情况的委托方法?或许还有另一种方式?

这是我目前的代码:

// View creation and adding to parent
NewViewController* newViewController = [[newViewController alloc] initWithNibName:@"NewViewController" bundle:nil];
[self.view addSubview:newViewController.view];

// NewViewController.h
@interface NewViewController : UIViewController {
    IBOutlet UIScrollView*  scrollView;

    // other outlets and properties
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;

在IB中,NewViewController的视图包含scrollView,其中包含所有其他插座(标签,按钮)...... 目标是让NewViewController的scrollView调用NewViewController的touchesBegan和touchesEnded方法。

更新: ScrollViewSuite帮助我了解了如何处理触摸回调。 UIScrollView仅在触摸无法滚动时调用它们。

所以,有三种情况:

  • 倾斜滑动(即使稍微显示滚动条):不调用touches方法
  • 完全水平幻灯片(不显示滚动条):touchesBegantouchesMovedtouchesEnded被称为
  • 任何不会导致滚动的触摸(触摸不移动或水平移动),然后是略微垂直的幻灯片:touchesBegantouchesMovedtouchesCancelled被调用;

通过将UIScrollView的{​​{1}}设置为canCancelContentTouches可以避免触摸取消,但这显然只有在调用FALSE时才有效,这意味着触摸方法仍然会没有被要求第一个案例。

但是touchesBegan有一个名为delaysContentTouches的属性,默认情况下设置为UIScrollView,并且当触摸开始时它会等待一点,以便查看它是否会让他滚动。如果将其设置为TRUE,则只要触摸开始就会调用触摸方法,并允许子类按照自己的意愿处理它们。

TL; DR:对我来说最简单的方法(如果你不能使用FALSE)是为了UIGestureRecognizer的子类,设置它的{{1 }}属性到UIScrollView并根据您的需要覆盖触摸函数(delayContentTouches / FALSE以及touchesShouldBegin / touchesShouldCancel ...)。

2 个答案:

答案 0 :(得分:6)

如果您正在为iPhone OS 3.2或更高版本构建,则可以使用Gesture Recognizer对象。根据您的描述,听起来您需要UIPanGestureRecognizerUISwipeGestureRecognizer。实例化适当的对象,使用[addGestureRecognizer:]方法将其添加到viewController的视图中,并在viewController中实现委托方法。

供参考:
iPhone Event Handling Guide: Gesture Recognizers
UIGestureRecognizer Reference(抽象超类)
UIGestureRecognizerDelegate Protocol Reference

答案 1 :(得分:1)

您的viewController视图应该是UIScrollView的子视图。 创建一个UIScrollView添加为窗口的子视图,然后创建一个viewController的实例,该实例具有滑块并添加到scrollView的子视图。

UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:[window bounds]];
[window addSubView:scrollView];
UIViewController *vc = [[UIViewController alloc] initWithNibNamed:@"MyVC" bundle:nil];
[scrollView addSubView:[vc view]];

我怀疑您是因为缺少IB中的连接而没有收到事件,或者scrollView正在将事件转发到newViewController视图的超级视图。

UIResponder nextResponder属性的Apple文档中。

  

UIResponder类不会自动存储或设置下一个响应者,而是默认返回nil。子类必须覆盖此方法以设置下一个响应者。 UIView通过返回管理它的UIViewController对象(如果有的话)或超级视图(如果没有)来实现此方法; UIViewController通过返回其视图的superview来实现该方法; UIWindow返回应用程序对象,UIApplication返回nil。

要尝试的事情。

  1. 在NewViewController.m中,覆盖canBecomeFirstResponder
    
    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
  2. 因为您只是将新视图添加为子视图而不是使用导航或模态视图,所以请确保newViewController的superview不再是第一个响应者。加:
    
    // View creation and adding to parent
    NewViewController* newViewController = [[newViewController alloc] initWithNibName:@"NewViewController" bundle:nil];
    [self.view addSubview:newViewController.view];
    [self.view resignFirstResponder];
    
  3. 确保`NextViewController'视图已连接到IB中的文件所有者。
  4. 确保视图的userInteractionEnabled属性为YES
  5. 同时查看ScrollViewSuite示例代码。 我注意到包含从scrollView接收事件的视图的控制器实现了视图的委托方法。您可以尝试的方法是在scrollView中子类化视图,并根据示例代码将事件处理委托给您的控制器。

    还有其他答案中讨论的新UIGesturizer的样本。请注意,将guest化器添加到视图中,并将guest化器的处理委托给另一个对象(通常是视图的控制器)

    您声明按钮和标签是作为IB中滚动视图的子视图添加的。看来你应该有一个UIView作为按钮和标签的容器。只是一个我无法从代码片段中分辨出来的想法。

    UIScrollView
      -> UIView
          ->UIButton
          ->UILabel
          ..
          ..