iPhone - обработка сенсорного слайда в UIViewController

Я хотел бы обрабатывать прикосновения (в частности, горизонтальный слайд) в подклассе 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, который содержит все другие выходы (метки, кнопки) ... Цель состоит в том, чтобы получить scrollView NewViewController для вызова методов touchesBegan и touchesEnded NewViewController.

Обновление: ScrollViewSuite очень помог мне понять, как обрабатываются обратные вызовы касаний. UIScrollView вызывает их только тогда, когда прикосновения не заставляют его прокручиваться.

Итак, три случая:

  • Наклонное скольжение (даже немного, как только появляется полоса прокрутки): метод touches не вызывается
  • Идеально горизонтальный слайд (полоса прокрутки не появляется): вызываются touchesBegan, touchesMoved и touchesEnded
  • Любое прикосновение, которое не вызывает прокрутки (касание без перемещения или горизонтальное перемещение), за которым следует слегка вертикальное скольжение: вызываются touchesBegan, touchesMoved и touchesCancelled;

Отмена касаний можно избежать, установив для UIScrollView canCancelContentTouches значение FALSE, но это, очевидно, работает только в том случае, если был вызван touchesBegan, что означает, что методы касаний по-прежнему не будут вызываться для первого случая.

Но UIScrollView имеет свойство, называемое delaysContentTouches, которое по умолчанию установлено на TRUE и заставляет его немного подождать, когда начинается прикосновение, чтобы увидеть, заставит ли оно его прокрутить. Если установлено значение FALSE, методы касания вызываются, как только начинается касание, и позволяют подклассам обрабатывать их по своему усмотрению.

TL; DR: Мне кажется, что самый простой способ (если вы не можете использовать UIGestureRecognizer) - создать подкласс UIScrollView, установить для его свойства delayContentTouches значение FALSE и переопределить функции касаний (также touchesShouldBegin / touchesShouldCancel как touchesBegan / _24 _...) в соответствии с вашими потребностями.


person Jukurrpa    schedule 22.06.2010    source источник
comment
Где вы устанавливаете свойство contentSize scrollView?   -  person falconcreek    schedule 23.06.2010
comment
В представлении NewViewController в viewDidLoad. Я размещаю свои розетки в соответствии с их размером, а в конце устанавливаю высоту содержимого scrollView. Но с этой прокруткой кода проблема только в том, что методы касаний не вызываются.   -  person Jukurrpa    schedule 23.06.2010


Ответы (2)


Если вы разрабатываете для iPhone OS 3.2 или выше, вы можете использовать объекты Gesture Recognizer. Судя по вашему описанию, вам нужен UIPanGestureRecognizer или UISwipeGestureRecognizer. Создайте экземпляр соответствующего объекта, добавьте его в представление viewController с помощью метода [addGestureRecognizer:] и реализуйте методы делегата в вашем viewController.

Для справки:
Руководство по обработке событий iPhone: распознаватели жестов
Справочник по UIGestureRecognizer (абстрактный суперкласс)
Справочник по протоколу UIGestureRecognizerDelegate

person Endemic    schedule 22.06.2010
comment
Раньше я собирал для iOS 3.1.3, и iPhone, над которым я работаю, сейчас тоже 3.1.3. Если я не могу найти ничего простого, я попробую обновить и изучить эти распознаватели жестов, спасибо. - person Jukurrpa; 22.06.2010

Представление вашего viewController должно быть подвидом UIScrollView. Создайте UIScrollView add как subView окна, затем создайте экземпляр вашего viewController, у которого есть ползунок, и добавьте в subview 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.

В документации Apple для свойства UIResponder nextResponder.

Класс UIResponder не сохраняет и не устанавливает следующего ответчика автоматически, вместо этого по умолчанию возвращает nil. Подклассы должны переопределить этот метод, чтобы установить следующего респондента. UIView реализует этот метод, возвращая объект UIViewController, который им управляет (если он есть) или его супервизор (если нет); UIViewController реализует метод, возвращая супервизор своего представления; UIWindow возвращает объект приложения, а UIApplication возвращает ноль.

Пара вещей, которые стоит попробовать.

  1. В NewViewController.m переопределите canBecomeFirstResponder
    
    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
  2. Поскольку вы просто добавляете свое новое представление в качестве подпредставления вместо использования навигации или модальных представлений, убедитесь, что супервизор newViewController больше не является первым респондентом. Добавить:
    
    // 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 для представления.

Взгляните также на пример кода ScrollViewSuite . Я заметил, что контроллер, содержащий представление, которое получает события от scrollView, реализует методы делегата для представления. Подход, который вы можете попробовать, состоит в том, чтобы создать подкласс представлений внутри scrollView и делегировать обработку событий вашему контроллеру в соответствии с образцом кода.

Есть также образцы для новых UIGesturizer, обсуждаемых в других ответах. Обратите внимание, что гостевизаторы добавляются к представлениям, а обработка гостевизаторов делегируется другому объекту (обычно контроллеру представления).

Вы заявили, что кнопки и метки добавляются как подпредставления прокрутки в IB. Кажется, у вас должен быть UIView в качестве контейнера для ваших кнопок и меток. Просто мысль, которую я не могу понять из фрагмента кода.

UIScrollView
  -> UIView
      ->UIButton
      ->UILabel
      ..
      ..
person falconcreek    schedule 22.06.2010
comment
Хм, я не уверен, что понимаю вашу точку зрения. Дело в том, что мое представление viewControllers уже является подвидом другого представления VC с предыдущего экрана в приложении, поэтому я попытался удалить scrollView из пера, создать его вручную, как вы это делаете в моем текущем представлении VC viewDidLoad, добавьте его в супервизор VC , и, наконец, добавьте представление VC для subviews scrollView. Но это ничего не делает, я не получаю ни прокрутки, ни обратных вызовов touchBegan / Ended. - person Jukurrpa; 22.06.2010
comment
Я обновил свой вопрос исходным кодом. Однако здесь особо не на что смотреть. - person Jukurrpa; 23.06.2010
comment
Я переопределил canBecomeFirstResponder, отказался от первого респондента супервизора и проверил все в IB, методы касаний по-прежнему не вызываются. Сначала я попробовал то, о чем думал, я создал подкласс UIScrollView, который переопределяет методы касаний (сохраняет некоторые данные перед вызовом [супер касания ...]) и заменил им свой scrollView. Это работает, но эти методы не вызываются каждый раз ... Это даже довольно случайно. Мне нужно медленно скользить и избегать прокрутки, если я хочу быть уверенным, что вызываются оба метода, как будто это какой-то фильтр ... Не похоже на хороший метод. - person Jukurrpa; 23.06.2010
comment
Добавлено еще несколько вещей, которые стоит попробовать - person falconcreek; 24.06.2010
comment
Извините за задержку, я работал над другими вещами. Думаю, я нашел решение, обновил исходный вопрос. Сейчас посмотрю, возможно ли все вручную обработать. Большое спасибо за вашу помощь, ScrollViewSuite оказался хорошей идеей. - person Jukurrpa; 25.06.2010