Прокрутка с двумя пальцами с UIScrollView

Вы можете попробовать:

new_df = df[df.Task1.str.contains("Drafting") | df.Task2.str.contains("Drafting") | df.Task3.str.contains("Drafting")]

Это вернет new_df со строками, содержащими «Чертеж» в любом из столбцов «Задача 1,2,3».

42
задан Srikar Appalaraju 22 September 2011 в 19:41
поделиться

6 ответов

You need to subclass UIScrollView (of course!). Then you need to:

  • make single-finger events to go to your content view (easy), and

  • make two-finger events scroll the scroll view (may be easy, may be hard, may be impossible).

Patrick's suggestion is generally fine: let your UIScrollView subclass know about your content view, then in touch event handlers check the number of fingers and forward the event accordingly. Just be sure that (1) the events you send to content view don't bubble back to UIScrollView through the responder chain (i.e. make sure to handle them all), (2) respect the usual flow of touch events (i.e. touchesBegan, than some number of {touchesBegan, touchesMoved, touchesEnded}, finished with touchesEnded or touchesCancelled), especially when dealing with UIScrollView. #2 can be tricky.

If you decide the event is for UIScrollView, another trick is to make UIScrollView believe your two-finger gesture is actually a one-finger gesture (because UIScrollView cannot be scrolled with two fingers). Try passing only the data for one finger to super (by filtering the (NSSet *)touches argument — note that it only contains the changed touches — and ignoring events for the wrong finger altogether).

If that does not work, you are in trouble. Theoretically you can try to create artificial touches to feed to UIScrollView by creating a class that looks similar to UITouch. Underlying C code does not check types, so maybe casting (YourTouch *) into (UITouch *) will work, and you will be able to trick UIScrollView into handling the touches that did not really happen.

You probably want to read my article on advanced UIScrollView tricks (and see some totally unrelated UIScrollView sample code there).

Of course, if you can't get it to work, there's always an option of either controlling UIScrollView's movement manually, or use an entirely custom-written scroll view. There's TTScrollView class in Three20 library; it does not feel good to the user, but does feel good to programmer.

10
ответ дан 26 November 2019 в 23:18
поделиться

Да, вам нужно создать подкласс UIScrollView и переопределить его - touchesBegan: и -touchesEnded: методы для передачи касаний «вверх». Это, вероятно, также будет включать в себя подкласс, имеющий переменную-член UIView , чтобы он знал, что он должен передать касаниям.

0
ответ дан 26 November 2019 в 23:18
поделиться

Плохие новости: iPhone SDK 3.0 и выше, не надо ' t передать касания к методам подкласса -touchesBegan: и - touchesEnded: ** UIScrollview **. Вы можете использовать методы touchesShouldBegin и touchesShouldCancelInContentView , которые не совпадают.

Если вы действительно хотите получить эти штрихи, используйте один хак , который позволяет это .

В вашем подклассе UIScrollView переопределите метод hitTest следующим образом:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;

  return result;
}

Это передаст вам подкласс этих касаний, однако вы не можете отменить прикосновения к UIScrollView суперкласс.

Вы можете использовать методы touchesShouldBegin и touchesShouldCancelInContentView , которые не совпадают.

Если вы действительно хотите получить эти штрихи, используйте один хак , который позволяет это .

В вашем подклассе UIScrollView переопределите метод hitTest следующим образом:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;

  return result;
}

Это передаст вам подкласс этих касаний, однако вы не можете отменить прикосновения к UIScrollView суперкласс.

Вы можете использовать методы touchesShouldBegin и touchesShouldCancelInContentView , которые не совпадают.

Если вы действительно хотите получить эти штрихи, используйте один хак , который позволяет это .

В вашем подклассе UIScrollView переопределите метод hitTest следующим образом:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;

  return result;
}

Это передаст вам подкласс этих касаний, однако вы не можете отменить прикосновения к UIScrollView суперкласс.

t отменить прикосновения к суперклассу UIScrollView .

t отменить прикосновения к суперклассу UIScrollView .

1
ответ дан 26 November 2019 в 23:18
поделиться

Что я делаю, так это то, что мой контроллер представления настраивает представление прокрутки:

[scrollView setCanCancelContentTouches:NO];
[scrollView setDelaysContentTouches:NO];

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

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // Hand tool or two or more touches means a pan or zoom gesture.
    if ((selectedTool == kHandToolIndex) || (event.allTouches.count > 1)) {
        [[self parentScrollView] setCanCancelContentTouches:YES];
        [firstTouchTimer invalidate];
        firstTouchTimer = nil;
        return;
    }

    // Use a timer to delay first touch because two-finger touches usually start with one touch followed by a second touch.
    [[self parentScrollView] setCanCancelContentTouches:NO];
    anchorPoint = [[touches anyObject] locationInView:self];
    firstTouchTimer = [NSTimer scheduledTimerWithTimeInterval:kFirstTouchTimeInterval target:self selector:@selector(firstTouchTimerFired:) userInfo:nil repeats:NO];
    firstTouchTimeStamp = event.timestamp;
}

Если второе событие touchesBegan: происходит с более чем одним пальцем, просмотр прокрутки может отменить касания. Поэтому, если пользователь панорамирует двумя пальцами, это представление получит сообщение touchesCanceled: .

1
ответ дан 26 November 2019 в 23:18
поделиться

Кажется, это лучший ресурс по этому вопросу в Интернете. Другое близкое решение можно найти здесь .

Я решил эту проблему весьма удовлетворительным образом другим способом, по сути, заменив мой собственный распознаватель жестов в уравнение. Я настоятельно рекомендую всем, кто пытается достичь эффекта, запрошенного исходным плакатом, рассмотреть эту альтернативу по сравнению с агрессивным подклассом UIScrollView .

Следующий процесс предоставит:

  • UIScrollView , содержащий ваше пользовательское представление

  • Масштабирование и панорамирование двумя пальцами (через UIPinchGestureRecognizer )

  • Обработка событий вашего представления для всех остальных касаний

Во-первых, предположим, что у вас есть контроллер представления и его представление. В IB сделайте представление подчиненным представлением scrollView и настройте правила изменения размера представления, чтобы оно не изменялось. В атрибутах scrollview включите все, что говорит «bounce», и выключите « delaysContentTouches ». Также вы должны установить минимальное и максимальное масштабирование, отличное от значения по умолчанию 1.0, поскольку, как говорится в документации Apple, это необходимо для работы масштабирования.

Создайте собственный подкласс UIScrollView и сделайте этот scrollview этим настраиваемым подклассом. Добавьте выход к вашему контроллеру представления для scrollview и подключите их. Теперь вы полностью настроены.

Вам нужно будет добавить следующий код в подкласс UIScrollView , чтобы он прозрачно передавал события касания (я подозреваю, что это можно было бы сделать более элегантно, возможно, даже полностью обойдя подкласс):

#pragma mark -
#pragma mark Event Passing

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesEnded:touches withEvent:event];
}
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
    return NO;
}

Добавить этот код для вашего контроллера представления:

- (void)setupGestures {
    UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
    [self.view addGestureRecognizer:pinchGesture];
    [pinchGesture release];
}

- (IBAction)handlePinchGesture:(UIPinchGestureRecognizer *)sender {
if ( sender.state == UIGestureRecognizerStateBegan ) {
    //Hold values
    previousLocation = [sender locationInView:self.view];
    previousOffset = self.scrollView.contentOffset;
    previousScale = self.scrollView.zoomScale;
} else if ( sender.state == UIGestureRecognizerStateChanged ) {
    //Zoom
    [self.scrollView setZoomScale:previousScale*sender.scale animated:NO];

    //Move
    location = [sender locationInView:self.view];
    CGPoint offset = CGPointMake(previousOffset.x+(previousLocation.x-location.x), previousOffset.y+(previousLocation.y-location.y));
    [self.scrollView setContentOffset:offset animated:NO];  
} else {
    if ( previousScale*sender.scale < 1.15 && previousScale*sender.scale > .85 )
        [self.scrollView setZoomScale:1.0 animated:YES];
}

}

Обратите внимание, что в этом методе есть ссылки на ряд свойств, которые вы должны определить в файлах классов вашего контроллера представления:

  • CGFloat previousScale;
  • CGPoint previousOffset;
  • CGPoint previousLocation;
  • CGPoint location;

Хорошо, вот и все!

К сожалению, мне не удалось заставить scrollView отображать свои скроллеры во время жеста. Я испробовал все эти стратегии:

//Scroll indicators
self.scrollView.showsVerticalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
[self.scrollView flashScrollIndicators];
[self.scrollView setNeedsDisplay];

Одна вещь, которая мне очень понравилась, - если вы посмотрите на последнюю строку, вы заметите, что она захватывает любое окончательное масштабирование, составляющее около 100%, и просто округляет его до этого. Вы можете отрегулировать свой уровень толерантности; Я видел это в поведении масштабирования Pages и подумал, что это было бы неплохо.

1
ответ дан 26 November 2019 в 23:18
поделиться

В SDK 3.2 обработка касаний для UIScrollView осуществляется с помощью распознавателей жестов.

Если вы хотите сделать двухпальцевое панорамирование вместо однопальцевого по умолчанию, вы можете использовать следующий код:

for (UIGestureRecognizer *gestureRecognizer in scrollView.gestureRecognizers) {     
    if ([gestureRecognizer  isKindOfClass:[UIPanGestureRecognizer class]]) {
        UIPanGestureRecognizer *panGR = (UIPanGestureRecognizer *) gestureRecognizer;
        panGR.minimumNumberOfTouches = 2;               
    }
}
64
ответ дан 26 November 2019 в 23:18
поделиться