Добавление пинч-масштабирования в UICollectionView

IntroI»

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

Наиболее релевантный код находится в нижней части вопроса для быстрого доступа. Вы можетеСкачать почтовый индекс источника или получить проект какMercurial Repository в BitBucket. Проект теперь включает в себя исправления из ответа ниже. Если вы хотите, чтобы изначально была сломанная версия, она помечается как "начально-багги-версия»

Проект является минимальным доказательством концепции / всплеска, чтобы оценить, является ли эффект жизнеспособным, поэтомудовольно легко и просто!

Желаемый эффект

Приложение будет отображать большое количество отдельных строк информации, которые образуют вертикальную таблицу. Таблица будет вертикально прокручиваться пользователем. Это стандартное поведение сUITableViewи вы можете использоватьUICollectionView тоже. Тем не менее, приложение также должно поддерживать масштабирование. Когда вы ущипните зум на столе,все из линий должны сжаться вместе. Пока ты растягиваешься,все из линий должны раздвинуться.

В моем доказательстве концепции размеры отдельных ячеек не меняются, они просто перемещаются ближе друг к другу или дальше друг от друга. Это намеренно: я нене верю в этокритически важно для подтверждения идеис осуществимость.

Вот'Снимки экрана показывают, как выглядит и масштабируется текущее приложение:

 

Текущая реализацияI '

м, используяUICollectionView с обычаемUICollectionViewLayout подкласс. Расположение размещаетUICollectionViewCells в хорошей шаткой синусоиде вниз по середине экрана. каждыйUICollectionViewCell это просто контейнер дляUILabel держаindexPath строка.

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

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

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

Распознаватель жестов также должен приспосабливать перетаскивания, возникающие при зажатии. Это также обрабатывается путем измененияUICollectionViewcontentOffset, Некоторый дополнительный код позволяет изменять центральную точку сенсорного жеста при добавлении / удалении пальцев из жеста.

Обратите внимание, чтоUICollectionView, бытьUIScrollView подкласс, имеет свойUIPanGestureRecognizer который взаимодействует сUIPinchGestureRecogniser добавил я. Я не уверен, вызывает ли это проблему или нет.

Я добавил код, чтобы отключитьUICollectionViewвстроена прокрутка во время моего жеста щепотка, но это неКажется, это не имеет большого значения. Я пытался использоватьgestureRecognizer:shouldRequireFailureOfGestureRecognizer: сделать мойUIPinchGestureRecognizer подвести встроенныйUIPanGestureRecognizer, но это вместо этого, казалось, остановило мой распознаватель пинча вообще. Я неНе знаю, глуп ли я, или это ошибка в iOS.

Как упоминалось ранее, текущаяUICollectionViewCellРазмеры не изменяются. Они просто переставлены. Это намеренно. Я нене думаю, что этоЭто важно для подтверждения этой концепции.

Что работает

Рабочие биты работают довольно хорошо. Вы можете перетащить стол вверх и вниз. Во время перетаскивания вы можете добавить палец и начать пинч, затем отпустить палец и продолжить перетаскивание, затем добавить и ущипнуть и т. Д.Все довольно гладко. На оригинальном iPhone 5 он плавно поддерживает пинч и панорамирование с помощью> 200 просмотров на экране.

Что нет работа 1

Если вы попытаетесь ущипнуть, когда верх или низ изображения на экране, все это немного сходит с ума.

На свитках вид можно перетаскивать так, чтобы он вытягивался за пределы видимого содержимого (что я хочу, так какстандартное поведение для списка данных на iOS).При изменении масштаба, однако, представление отодвигается назад, так что содержимое закрепляется на экране (я нене хочу, чтобы это произошло).

Эти двое сражаются друг с другом во время жеста «щепотка», из-за которого содержимое сильно мерцает вверх и вниз (чего я определенно не хочуне хочу!).

Что нет работа 2

'UICollectionViewПо умолчанию прокрутка имеет замедление, если вы отпускаете во время прокрутки, а также плавно отскакивает содержимое назад, когда вы прокручиваете за его пределами. Это нет в настоящее время обрабатываются вообще.

Если вы отпустите жест щипка во время прокрутки, он просто остановится.Если вы прокручиваете содержимое с помощью жеста, а затем отпускаете, оно остается на месте и не отображается.не оправиться. Когда вы снова начинаете прокрутку, происходит возврат содержимого обратно.Вещи, которые ямы пытались, но не моглит на работу

UICollectionView, бытьUIScrollView должен иметь встроенныйUIPinchGestureRecogniser если оно's настроен правильно для поддержки масштабирования. Я задавался вопросом, могу ли я использовать это вместо того, чтобы иметь свой собственныйUIPinchGestureRecogniser, Я попытался настроить это, установив минимальную и максимальную шкалы и добавив свой контроллерS щепотка обработчик. Тем не менее, я нене понимаю, что я должен возвращаться из моей реализацииviewForZoomingInScrollView:, так что я'м просто создаю фиктивный вид с[[UIView alloc] initWithFrame: [[self collectionView] bounds]], Это делает вид прокрутки "коллапс» в одну строку, которая нет ям после!

Наконец (перед кодом)

Это длинный вопрос, поэтому спасибо, что прочитали его. Спасибо еще больше, если вы можете помочь с ответом. Я'извините, если много чего ясказал или добавил не имеет значения!

Код для контроллера вида
//  STViewController.m
#import "STViewController.h"
#import "STDataColumnsCollectionViewLayout.h"
#import "STCollectionViewLabelCell.h"

@interface STViewController () 
@property (nonatomic, assign) CGFloat pinchStartVerticalPeriod;
@property (nonatomic, assign) CGFloat pinchNormalisedVerticalPosition;
@property (nonatomic, assign) NSInteger pinchTouchCount;
-(void) handlePinch: (UIPinchGestureRecognizer *) pinchRecogniser;
@end

@implementation STViewController

-(void) viewDidLoad
{
  [[self collectionView] registerClass: [STCollectionViewLabelCell class] forCellWithReuseIdentifier: [STCollectionViewLabelCell className]];

  UICollectionView *const collectionView = [self collectionView];
  [collectionView setAllowsSelection: NO];

  [_pinchRecogniser addTarget: self action: @selector(handlePinch:)];
  [_pinchRecogniser setDelegate: self];
  [_pinchRecogniser setCancelsTouchesInView:YES];
  [[self view] addGestureRecognizer: _pinchRecogniser];
}

#pragma mark -

-(NSInteger) collectionView: (UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
  return 800;
}

-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
  STCollectionViewLabelCell *const cell = [[self collectionView] dequeueReusableCellWithReuseIdentifier: [STCollectionViewLabelCell className] forIndexPath: indexPath];
  [[cell label] setText: [NSString stringWithFormat: @"%d", [indexPath row]]];
  return cell;
}

#pragma mark -

-(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
  return YES;
}

#pragma mark -

-(void) handlePinch: (UIPinchGestureRecognizer *) pinchRecogniser
{
  UICollectionView *const collectionView = [self collectionView];
  STDataColumnsCollectionViewLayout *const layout = (STDataColumnsCollectionViewLayout *)[self collectionViewLayout];

  if(([pinchRecogniser state] == UIGestureRecognizerStateBegan) || ([pinchRecogniser numberOfTouches] != _pinchTouchCount))
  {
    const CGFloat normalisedY = [pinchRecogniser locationInView: collectionView].y / [layout collectionViewContentSize].height;
    _pinchNormalisedVerticalPosition = normalisedY;
    _pinchTouchCount = [pinchRecogniser numberOfTouches];
  }

  switch ([pinchRecogniser state])
  {
    case UIGestureRecognizerStateBegan:
    {
      NSLog(@"Began");
      _pinchStartVerticalPeriod = [layout verticalPeriod];
      [collectionView setScrollEnabled: NO];
      break;
    }

    case UIGestureRecognizerStateChanged:
    {
      NSLog(@"Changed");
      STDataColumnsCollectionViewLayout *const layout = (STDataColumnsCollectionViewLayout *)[self collectionViewLayout];
      const CGFloat newVerticalPeriod = _pinchStartVerticalPeriod * [pinchRecogniser scale];
      [layout setVerticalPeriod: newVerticalPeriod];
      [[self collectionViewLayout] invalidateLayout];

      const CGPoint dragCenter = [pinchRecogniser locationInView: [collectionView superview]];
      const CGFloat currentY = _pinchNormalisedVerticalPosition * [layout collectionViewContentSize].height;
      [collectionView setContentOffset: CGPointMake(0, currentY - dragCenter.y) animated: NO];
    }

    case UIGestureRecognizerStateEnded:
    case UIGestureRecognizerStateCancelled:
    {
      [collectionView setScrollEnabled: YES];
    }

    default:
      break;
  }
}

@end

Ответы на вопрос(1)

Ваш ответ на вопрос