UIScrollView: подкачка по горизонтали, прокрутка по вертикали?

Как я могу заставить UIScrollView в котором пейджинг и прокрутка включены, чтобы двигаться только вертикально или горизонтально в данный момент?

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

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

Должен сказать, вы в очень тяжелой ситуации.

Обратите внимание, что вам нужно использовать UIScrollView с pagingEnabled=YES для переключения между страницами, но вам нужно pagingEnabled=NO для прокрутки по вертикали.

Существует две возможные страtagsи. Я не знаю, какой из них будет работать / проще реализовать, поэтому попробуйте оба.

Во-первых: вложенные UIScrollViews. Честно говоря, я еще должен увидеть человека, у которого есть это, чтобы работать. Однако я не очень старался лично, и моя практика показывает, что, когда вы достаточно стараетесь, вы можете сделать UIScrollView делать что угодно .

Таким образом, страtagsя заключается в том, чтобы внешний вид прокрутки обрабатывал только горизонтальную прокрутку и внутренние прокрутки, чтобы обрабатывать только вертикальную прокрутку. Для этого вы должны знать, как работает UIScrollView. Он переопределяет метод hitTest и всегда возвращает себя, так что все события касания переходят в UIScrollView. Затем внутри touchesBegan , touchesMoved т. Д., Он проверяет, заинтересован ли он в событии, и либо обрабатывает, либо передает его внутренним компонентам.

Чтобы решить, нужно ли обрабатывать или пересылать касание, UIScrollView запускает таймер при первом касании:

  • Если вы не перенесли палец значительно в течение 150 мс, он передает событие во внутренний вид.

  • Если вы перенесли палец значительно в течение 150 мс, он начинает прокрутку (и никогда не передает событие во внутренний вид).

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

  • Если вы не пошевелили пальцем в течение 150 мс, а UIScrollView начал передавать события во внутренний вид, но затем вы перенесли палец достаточно далеко, чтобы начать прокрутку, UIScrollView вызывает touchesCancelled во внутреннем представлении и начинает прокрутку.

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

Эта последовательность событий может быть изменена с помощью конфигурации UIScrollView:

  • Если delaysContentTouches НЕТ, то таймер не используется – события немедленно переходят во внутренний контроль (но затем отменяются, если вы достаточно далеко перемещаете палец)
  • Если cancelsTouches – нет, то, как только события будут отправлены в элемент управления, прокрутки никогда не произойдет.

Обратите внимание, что это UIScrollView, который получает все touchesEnded , touchesEnded , touchesEnded и touchesCanceled из CocoaTouch (потому что его hitTest сообщает ему об этом). Затем он пересылает их во внутренний вид, если захочет, до тех пор, пока он этого захочет.

Теперь, когда вы знаете все о UIScrollView, вы можете изменить его поведение. Я могу поспорить, что вы хотите отдать предпочтение вертикальной прокрутке, так что, как только пользователь коснется представления и начнет перемещать свой палец (даже слегка), вид начинает прокручиваться в вертикальном направлении; но когда пользователь перемещает палец в горизонтальном направлении достаточно далеко, вы хотите отменить вертикальную прокрутку и начать горизонтальную прокрутку.

Вы хотите подclassифицировать внешний UIScrollView (например, вы называете свой class RemorsefulScrollView), так что вместо поведения по умолчанию он сразу пересылает все события во внутренний вид и только когда обнаруживается значительное горизонтальное движение, оно прокручивается.

Как сделать make RemorsefulScrollView так себя вести?

  • Похоже, что отключение вертикальной прокрутки и установка delaysContentTouches в значение NO должно привести к тому, что вложенные UIScrollViews будут работать. К сожалению, это не так; UIScrollView, похоже, выполняет некоторую дополнительную фильтрацию для быстрых движений (которые нельзя отключить), так что даже если UIScrollView можно прокручивать по горизонтали, он всегда будет потреблять (и игнорировать) достаточно быстрые вертикальные движения.

    Эффект настолько серьезен, что вертикальная прокрутка внутри вложенного вида прокрутки непригодна. (Похоже, что у вас есть именно эта настройка, поэтому попробуйте: держите палец на 150 мс, а затем переместите его в вертикальном направлении – вложенный UIScrollView работает так, как ожидалось!)

  • Это означает, что вы не можете использовать код UIScrollView для обработки событий; вы должны переопределить все четыре метода обработки касания в RemorsefulScrollView и сначала выполнить свою собственную обработку, только пересылку события в super (UIScrollView), если вы решили перейти с горизонтальной прокруткой.

  • Однако вам нужно передать touchesBegan в UIScrollView, потому что вы хотите, чтобы он запоминал базовую координату для будущей горизонтальной прокрутки (если позже вы решите, что это горизонтальная прокрутка). Вы не сможете отправить touchesBegan в UIScrollView позже, потому что вы не можете сохранить аргумент touches : он содержит объекты, которые будут мутированы до следующего touchesMoved , и вы не можете воспроизвести старое состояние.

    Таким образом, вы должны немедленно передать touchesBegan в UIScrollView, но вы будете скрывать любые дальнейшие touchesMoved события от него, пока вы не решите прокручивать по горизонтали. Никаких touchesMoved не прокручивать, так что это начальное touchesBegan принесет никакого вреда. Но установите delaysContentTouches на NO, чтобы никакие дополнительные таймеры не мешали.

    (Offtopic – в отличие от вас, UIScrollView может хранить штрихи должным образом и может воспроизводить и пересылать исходные события touchesBegan позже. У него есть несправедливое преимущество использования неопубликованных API-интерфейсов, поэтому они могут клонировать объекты касания до того, как они будут мутированы.)

  • Учитывая, что вы всегда touchesCancelled touchesEnded , вам также нужно направить touchesCancelled и « touchesEnded . touchesCancelled менее, вы должны включить touchesEnded в touchesCancelled , потому что UIScrollView будет интерпретировать touchesEnded , touchesEnded последовательность как сенсорный щелчок и пересылает ее во внутренний вид. Вы уже сами отправляете правильные события, поэтому никогда не хотите, чтобы UIScrollView перенаправлял что-либо.

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

 // RemorsefulScrollView.h @interface RemorsefulScrollView : UIScrollView { CGPoint _originalPoint; BOOL _isHorizontalScroll, _isMultitouch; UIView *_currentChild; } @end // RemorsefulScrollView.m // the numbers from an example in Apple docs, may need to tune them #define kThresholdX 12.0f #define kThresholdY 4.0f @implementation RemorsefulScrollView - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.delaysContentTouches = NO; } return self; } - (id)initWithCoder:(NSCoder *)coder { if (self = [super initWithCoder:coder]) { self.delaysContentTouches = NO; } return self; } - (UIView *)honestHitTest:(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; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; // always forward touchesBegan -- there's no way to forward it later if (_isHorizontalScroll) return; // UIScrollView is in charge now if ([touches count] == [[event touchesForView:self] count]) { // initial touch _originalPoint = [[touches anyObject] locationInView:self]; _currentChild = [self honestHitTest:_originalPoint withEvent:event]; _isMultitouch = NO; } _isMultitouch |= ([[event touchesForView:self] count] > 1); [_currentChild touchesBegan:touches withEvent:event]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if (!_isHorizontalScroll && !_isMultitouch) { CGPoint point = [[touches anyObject] locationInView:self]; if (fabsf(_originalPoint.x - point.x) > kThresholdX && fabsf(_originalPoint.y - point.y) < kThresholdY) { _isHorizontalScroll = YES; [_currentChild touchesCancelled:[event touchesForView:self] withEvent:event] } } if (_isHorizontalScroll) [super touchesMoved:touches withEvent:event]; // UIScrollView only kicks in on horizontal scroll else [_currentChild touchesMoved:touches withEvent:event]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if (_isHorizontalScroll) [super touchesEnded:touches withEvent:event]; else { [super touchesCancelled:touches withEvent:event]; [_currentChild touchesEnded:touches withEvent:event]; } } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; if (!_isHorizontalScroll) [_currentChild touchesCancelled:touches withEvent:event]; } @end 

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

Единственный скрытый улов, который я вижу, заключается в том, что если вы добавите дочерние представления, отличные от UIScrollView, в RemorsefulScrollView, события касания, которые вы пересылаете ребенку, могут вернуться к вам через цепочку ответчиков, если ребенок не всегда обрабатывает такие атаки, как UIScrollView. Пуленепробиваемая реализация RemorsefulScrollView защитит от touchesXxx .

Вторая страtagsя: если по какой-то причине вложенные UIScrollViews не работают или слишком сложно получить право, вы можете попытаться pagingEnabled только с одним UIScrollView, переключив его свойство pagingEnabled на лету из вашего scrollViewDidScroll делегирования scrollViewDidScroll .

Чтобы предотвратить прокрутку по диагонали, сначала попробуйте запомнить contentOffset в scrollViewWillBeginDragging , а также проверить и сбросить содержимоеОфис внутри scrollViewDidScroll если вы обнаружите диагональное движение. Еще одна страtagsя - сбросить contentSize, чтобы включить только прокрутку в одном направлении, как только вы решите, в каком направлении движется палец пользователя. (UIScrollView кажется довольно прощающим о том, как возиться с contentSize и contentOffset из своих методов делегирования.)

Если это не работает или приводит к неаккуратным визуальным эффектам, вы должны переопределить touchesBegan , touchesMoved т. Д., А не пересылать диагональные события движения в UIScrollView. (В этом случае пользовательский опыт будет субоптимальным, потому что вам придется игнорировать диагональные движения, а не форсировать их в одном направлении. Если вы чувствуете себя очень авантюрно, вы можете написать свой собственный UITouch-подобный, что-то вроде RevengeTouch. -C - простой старый C, и в мире нет ничего глупого, кроме C, пока никто не проверяет реальный class объектов, который, как я полагаю, никто не делает, вы можете сделать любой class похожим на любой другой class. возможность синтезировать любые штрихи, которые вы хотите, с любыми координатами, которые вы хотите.)

Страtagsя резервного копирования: есть TTScrollView, разумная переоценка UIScrollView в библиотеке Three20 . К сожалению, он чувствует себя очень неестественным и не-iphonish для пользователя. Но если каждая попытка использования UIScrollView терпит неудачу, вы можете вернуться к пользовательскому кодированному представлению прокрутки. Я рекомендую против этого, если это вообще возможно; использование UIScrollView гарантирует, что вы получаете естественный внешний вид, независимо от того, как он развивается в будущих версиях ОС для iPhone.

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

PS Если вы получите какую-либо из этих работ и почувствуете, что хотите поделиться, напишите мне соответствующий код на [email protected], я бы с радостью включил его в свой трюк в ScrollingMadness.

PPS Добавление этого небольшого эссе в ScrollingMadness README.

Это работает для меня каждый раз …

 scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * NumberOfPages, 1); 

Для ленивых людей, таких как я:

Установите scrollview.directionalLockEnabled в YES

 - (void) scrollViewWillBeginDragging: (UIScrollView *) scrollView { self.oldContentOffset = scrollView.contentOffset; } - (void) scrollViewDidScroll: (UIScrollView *) scrollView { if (scrollView.contentOffset.x != self.oldContentOffset.x) { scrollView.pagingEnabled = YES; scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, self.oldContentOffset.y); } else { scrollView.pagingEnabled = NO; } } - (void) scrollViewDidEndDecelerating: (UIScrollView *) scrollView { self.oldContentOffset = scrollView.contentOffset; } 

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

Сначала определите следующие переменные в файле заголовков controllerов.

 CGPoint startPos; int scrollDirection; 

startPos будет сохранять значение contentOffset, когда ваш делегат получит сообщение scrollViewWillBeginDragging . Поэтому в этом методе мы делаем это;

 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ startPos = scrollView.contentOffset; scrollDirection=0; } 

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

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ if (scrollDirection==0){//we need to determine direction //use the difference between positions to determine the direction. if (abs(startPos.x-scrollView.contentOffset.x) 

наконец, мы должны остановить все операции обновления при перетаскивании конечного пользователя;

  - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if (decelerate) { scrollDirection=3; } } 

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

Я хочу отображать экранный контент, но позволяю пользователю прокручивать один из 4 других экранов, вверх и вниз влево и вправо. У меня есть один UIScrollView размером 320×480 и contentSize размером 960×1440. Смещение содержимого начинается с 320,480. В scrollViewDidEndDecelerating :, я перерисовываю 5 представлений (просмотры центра и 4 вокруг него) и сбрасывает смещение содержимого до 320,480.

Вот мясо моего решения, метод scrollViewDidScroll:.

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (!scrollingVertically && ! scrollingHorizontally) { int xDiff = abs(scrollView.contentOffset.x - 320); int yDiff = abs(scrollView.contentOffset.y - 480); if (xDiff > yDiff) { scrollingHorizontally = YES; } else if (xDiff < yDiff) { scrollingVertically = YES; } } if (scrollingHorizontally) { scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, 480); } else if (scrollingVertically) { scrollView.contentOffset = CGPointMake(320, scrollView.contentOffset.y); } } 

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

Вот моя реализация выгружаемого UIScrollView который разрешает только ортогональные свитки. Обязательно установите для pagingEnabled значение YES .

PagedOrthoScrollView.h

 @interface PagedOrthoScrollView : UIScrollView @end 

PagedOrthoScrollView.m

 #import "PagedOrthoScrollView.h" typedef enum { PagedOrthoScrollViewLockDirectionNone, PagedOrthoScrollViewLockDirectionVertical, PagedOrthoScrollViewLockDirectionHorizontal } PagedOrthoScrollViewLockDirection; @interface PagedOrthoScrollView () @property(nonatomic, assign) PagedOrthoScrollViewLockDirection dirLock; @property(nonatomic, assign) CGFloat valueLock; @end @implementation PagedOrthoScrollView @synthesize dirLock; @synthesize valueLock; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self == nil) { return self; } self.dirLock = PagedOrthoScrollViewLockDirectionNone; self.valueLock = 0; return self; } - (void)setBounds:(CGRect)bounds { int mx, my; if (self.dirLock == PagedOrthoScrollViewLockDirectionNone) { // is on even page coordinates, set dir lock and lock value to closest page mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds)); if (mx != 0) { self.dirLock = PagedOrthoScrollViewLockDirectionHorizontal; self.valueLock = (round(CGRectGetMinY(bounds) / CGRectGetHeight(self.bounds)) * CGRectGetHeight(self.bounds)); } else { self.dirLock = PagedOrthoScrollViewLockDirectionVertical; self.valueLock = (round(CGRectGetMinX(bounds) / CGRectGetWidth(self.bounds)) * CGRectGetWidth(self.bounds)); } // show only possible scroll indicator self.showsVerticalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionVertical; self.showsHorizontalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionHorizontal; } if (self.dirLock == PagedOrthoScrollViewLockDirectionHorizontal) { bounds.origin.y = self.valueLock; } else { bounds.origin.x = self.valueLock; } mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds)); my = abs((int)CGRectGetMinY(bounds) % (int)CGRectGetHeight(self.bounds)); if (mx == 0 && my == 0) { // is on even page coordinates, reset lock self.dirLock = PagedOrthoScrollViewLockDirectionNone; } [super setBounds:bounds]; } @end 

Мне также пришлось решить эту проблему, и хотя ответ Андрея Таранцова определенно содержит много полезной информации для понимания работы UIScrollViews , я считаю, что решение немного сложнее. Мое решение, которое не связано с подclassом или сенсорным переадресацией, выглядит следующим образом:

  1. Создайте два вложенных вида прокрутки, по одному для каждого направления.
  2. Создайте два фиктивных UIPanGestureRecognizers , снова по одному для каждого направления.
  3. Создавайте ошибки зависимостей между свойствами panGestureRecognizer UIScrollViews и манекеном UIPanGestureRecognizer соответствующим направлению, перпендикулярному желаемому направлению прокрутки UIScrollView, с помощью UIGestureRecognizer's -requireGestureRecognizerToFail:
  4. В -gestureRecognizerShouldBegin: обратные вызовы для ваших фиктивных идентификаторов UIPanGestureRecognizers, вычислите начальное направление панорамирования с помощью переключателя-трансляцииInView: селектора UIPanGestureRecognizers (ваши UIPanGestureRecognizers не будут вызывать этот обратный вызов делегата, пока ваш прикосновение не переведет достаточно, чтобы зарегистрироваться в качестве панорамирования). Разрешить или запретить распознавание жестов начать в зависимости от вычисленного направления, которое, в свою очередь, должно контролировать, будет ли разрешено перпендикулярное распознавание жеста UIScrollView.
  5. In -gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: не позволяйте вашим фиктивным UIPanGestureRecognizers работать вместе с прокруткой (если у вас нет дополнительного поведения, которое вы хотели добавить).

То, что я сделал, это создать пейджинговый UIScrollView с кадром размером экрана просмотра и установить размер содержимого в ширину, необходимую для всего моего контента, и высоту 1 (спасибо Tonetel). Затем я создал меню страниц UIScrollView с кадрами, установленными на каждой странице, размером экрана просмотра и задал размер содержимого каждого по ширине экрана и необходимую высоту для каждого из них. Затем я просто добавил каждую страницу меню в просмотр подкачки. Убедитесь, что пейджинг включен в просмотре прокрутки пейджинга, но отключен в представлениях меню (должен быть отключен по умолчанию), и вам должно быть хорошо идти.

Прокрутка пейджинга теперь прокручивается горизонтально, но не вертикально из-за высоты содержимого. Каждая страница прокручивается вертикально, но не горизонтально из-за ограничений по размеру содержимого.

Вот код, если это объяснение оставляет желать лучшего:

 UIScrollView *newPagingScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; [newPagingScrollView setPagingEnabled:YES]; [newPagingScrollView setShowsVerticalScrollIndicator:NO]; [newPagingScrollView setShowsHorizontalScrollIndicator:NO]; [newPagingScrollView setDelegate:self]; [newPagingScrollView setContentSize:CGSizeMake(self.view.bounds.size.width * NumberOfDetailPages, 1)]; [self.view addSubview:newPagingScrollView]; float pageX = 0; for (int i = 0; i < NumberOfDetailPages; i++) { CGRect pageFrame = (CGRect) { .origin = CGPointMake(pageX, pagingScrollView.bounds.origin.y), .size = pagingScrollView.bounds.size }; UIScrollView *newPage = [self createNewPageFromIndex:i ToPageFrame:pageFrame]; // newPage.contentSize custom set in here [pagingScrollView addSubview:newPage]; pageX += pageFrame.size.width; } 

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

 self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, 1); 

Это улучшенное решение icompot, которое для меня было довольно неустойчивым. Это хорошо работает, и его легко реализовать:

 - (void) scrollViewWillBeginDragging: (UIScrollView *) scrollView { self.oldContentOffset = scrollView.contentOffset; } - (void) scrollViewDidScroll: (UIScrollView *) scrollView { float XOffset = fabsf(self.oldContentOffset.x - scrollView.contentOffset.x ); float YOffset = fabsf(self.oldContentOffset.y - scrollView.contentOffset.y ); if (scrollView.contentOffset.x != self.oldContentOffset.x && (XOffset >= YOffset) ) { scrollView.pagingEnabled = YES; scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, self.oldContentOffset.y); } else { scrollView.pagingEnabled = NO; scrollView.contentOffset = CGPointMake( self.oldContentOffset.x, scrollView.contentOffset.y); } } - (void) scrollViewDidEndDecelerating: (UIScrollView *) scrollView { self.oldContentOffset = scrollView.contentOffset; } 

Из документов:

«значение по умолчанию -« НЕТ », что означает, что прокрутка разрешена в горизонтальном и вертикальном направлениях. Если значение« ДА »и пользователь начинает перетаскивать в одном общем направлении (горизонтально или вертикально), просмотр прокрутки отключает прокрутку в другом направлении. ”

Я думаю, что важной частью является «если … пользователь начинает таскать в одном общем направлении». Поэтому, если они начнут таскать по диагонали, это не влечет. Не то, чтобы эти документы всегда были надежными, когда дело доходило до интерпретации, – но это похоже на то, что вы видите.

Это на самом деле кажется разумным. Я должен спросить – почему вы хотите в любое время ограничиться только горизонтальным или вертикальным? Возможно, UIScrollView не является для вас инструментом?

Мой вид состоит из 10 горизонтальных представлений, и некоторые из этих представлений состоят из нескольких вертикальных представлений, поэтому вы получите что-то вроде этого:

 1.0 2.0 3.1 4.1 2.1 3.1 2.2 2.3 

С пейджингом, включенным как на горизонтальной, так и на вертикальной оси

Представление также имеет следующие атрибуты:

 [self setDelaysContentTouches:NO]; [self setMultipleTouchEnabled:NO]; [self setDirectionalLockEnabled:YES]; 

Теперь для предотвращения диагональной прокрутки выполните следующее:

 -(void)scrollViewDidScroll:(UIScrollView *)scrollView { int pageWidth = 768; int pageHeight = 1024; int subPage =round(self.contentOffset.y / pageHeight); if ((int)self.contentOffset.x % pageWidth != 0 && (int)self.contentOffset.y % pageHeight != 0) { [self setContentOffset:CGPointMake(self.contentOffset.x, subPage * pageHeight]; } } 

Работает, как чары для меня!

Необходимо сбросить _isHorizontalScroll в NO в touchesEnded и touchesCancelled .

Если у вас большой scrollview … и вы хотите ограничить диагональную прокрутку http://chandanshetty01.blogspot.in/2012/07/restricting-diagonal-scrolling-in.html

Для дальнейшего использования я основывался на ответе Андрея Танасова и придумал следующее решение, которое прекрасно работает.

Сначала определите переменную для хранения contentOffset и установите ее на 0,0 координаты

 var positionScroll = CGPointMake(0, 0) 

Теперь выполните в делегате scrollView следующее:

 override func scrollViewWillBeginDragging(scrollView: UIScrollView) { // Note that we are getting a reference to self.scrollView and not the scrollView referenced passed by the method // For some reason, not doing this fails to get the logic to work self.positionScroll = (self.scrollView?.contentOffset)! } override func scrollViewDidScroll(scrollView: UIScrollView) { // Check that contentOffset is not nil // We do this because the scrollViewDidScroll method is called on viewDidLoad if self.scrollView?.contentOffset != nil { // The user wants to scroll on the X axis if self.scrollView?.contentOffset.x > self.positionScroll.x || self.scrollView?.contentOffset.x < self.positionScroll.x { // Reset the Y position of the scrollView to what it was BEFORE scrolling started self.scrollView?.contentOffset = CGPointMake((self.scrollView?.contentOffset.x)!, self.positionScroll.y); self.scrollView?.pagingEnabled = true } // The user wants to scroll on the Y axis else { // Reset the X position of the scrollView to what it was BEFORE scrolling started self.scrollView?.contentOffset = CGPointMake(self.positionScroll.x, (self.scrollView?.contentOffset.y)!); self.collectionView?.pagingEnabled = false } } } 

Надеюсь это поможет.

Если вы не пробовали делать это в бета-версии 3.0, я рекомендую вам сделать снимок. В настоящее время я использую серию представлений таблиц внутри прокрутки и работает так, как ожидалось. (Ну, прокрутка, во всяком случае, нашла этот вопрос при поиске исправления совершенно другой проблемы …)

Для тех, кто смотрит в Swift на @AndreyTarantsov второе решение, похожее на это в коде:

  var positionScroll:CGFloat = 0 func scrollViewWillBeginDragging(scrollView: UIScrollView) { positionScroll = self.theScroll.contentOffset.x } func scrollViewDidScroll(scrollView: UIScrollView) { if self.theScroll.contentOffset.x > self.positionScroll || self.theScroll.contentOffset.x < self.positionScroll{ self.theScroll.pagingEnabled = true }else{ self.theScroll.pagingEnabled = false } } 

то, что мы делаем здесь, заключается в том, чтобы сохранить текущую позицию непосредственно перед drag and dropм прокрутки, а затем проверить, увеличилось или уменьшилось или x по сравнению с текущей позицией x. Если да, то установите для pagingEnabled значение true, если нет (y увеличилось / уменьшилось), то установите для pagingEnabled значение false

Надеюсь, что это полезно для новых гостей!

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

В построителе интерфейса просто нажмите на UIScrollView и выберите параметр (в инспекторе), который ограничивает его только прокруткой в ​​один проход.

  • Рисование поэтапно в UIView (iPhone)
  • Сериализация и десериализация объектов Objective-C в JSON
  • Как я могу перебирать все подпункты UIView, а также их подзоны и их подпрограммы
  • UIImage от CALayer - iPhone SDK
  • UIWebView не масштабирует контент для соответствия
  • Заголовок Swift для Objective-C, не созданный в Xcode 6
  • UIScrollView - показывает полосу прокрутки
  • Как обнаружить паузу во вводе для UISearchBar / UITextField?
  • IPhone / IPad: Как получить ширину экрана программно?
  • Как скопировать объект в объекте c
  • Как получить текущее название города?
  • Interesting Posts
    Давайте будем гением компьютера.