Добавление пинч-масштабирования в UICollectionView
Я собираюсь описать эффект, которого я хочу достичь, а затем ярасскажу как яВ настоящее время я пытаюсь реализовать это и чтонеправильно с его поведением, как оно есть. Я'также упомяну другой подход, который япосмотрел, но не смогвообще не работает.
Наиболее релевантный код находится в нижней части вопроса для быстрого доступа. Вы можетеСкачать почтовый индекс источника или получить проект какMercurial Repository в BitBucket. Проект теперь включает в себя исправления из ответа ниже. Если вы хотите, чтобы изначально была сломанная версия, она помечается как "начально-багги-версия»
Проект является минимальным доказательством концепции / всплеска, чтобы оценить, является ли эффект жизнеспособным, поэтомудовольно легко и просто!
Желаемый эффектПриложение будет отображать большое количество отдельных строк информации, которые образуют вертикальную таблицу. Таблица будет вертикально прокручиваться пользователем. Это стандартное поведение сUITableView
и вы можете использоватьUICollectionView
тоже. Тем не менее, приложение также должно поддерживать масштабирование. Когда вы ущипните зум на столе,все из линий должны сжаться вместе. Пока ты растягиваешься,все из линий должны раздвинуться.
В моем доказательстве концепции размеры отдельных ячеек не меняются, они просто перемещаются ближе друг к другу или дальше друг от друга. Это намеренно: я нене верю в этокритически важно для подтверждения идеис осуществимость.
Вот'Снимки экрана показывают, как выглядит и масштабируется текущее приложение:
Текущая реализацияI '
м, используяUICollectionView
с обычаемUICollectionViewLayout
подкласс. Расположение размещаетUICollectionViewCells
в хорошей шаткой синусоиде вниз по середине экрана. каждыйUICollectionViewCell
это просто контейнер дляUILabel
держаindexPath
строка.
UICollectionViewLayout
у подкласса есть параметр, чтобы установить вертикальный интервал между каждой ячейкой, которую он описывает,UICollectionView
и регулировка этого позволяет прижимать или растягивать стол по желанию.
мойUICollectionViewController
подкласс имеетUIPinchGestureRecognizer
, Когда распознаватель обнаруживает изменения масштаба, вертикальное расстояние между ячейками вUICollectionView
макет изменился соответственно.
Без дальнейшего рассмотрения масштабирование будет происходить с верхней части содержимого, а не вокруг центра сенсорного жеста. ЭтоUICollectionView
contentOffset
свойство настраивается во время сжатия, чтобы обеспечить эту функцию.
Распознаватель жестов также должен приспосабливать перетаскивания, возникающие при зажатии. Это также обрабатывается путем измененияUICollectionView
contentOffset
, Некоторый дополнительный код позволяет изменять центральную точку сенсорного жеста при добавлении / удалении пальцев из жеста.
Обратите внимание, что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