UIScrollview с UIButtons – как воссоздать трамплин?

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

Есть ли свойство или параметр, который заставляет кнопку отправлять события касания до своего родителя (супервизор)? Нужно ли добавлять кнопки к чему-то еще, прежде чем добавлять UIScrollView?

Вот мой код:

//init scrolling area UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 480, 480)]; scrollView.contentSize = CGSizeMake(480, 1000); scrollView.bounces = NO; scrollView.delaysContentTouches = NO; //create background image UIImageView *rowsBackground = [[UIImageView alloc] initWithImage:[self scaleAndRotateImage:[UIImage imageNamed:@"mylongbackground.png"]]]; rowsBackground.userInteractionEnabled = YES; //create button UIButton *btn = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; btn.frame = CGRectMake(100, 850, 150, 150); btn.bounds = CGRectMake(0, 0, 150.0, 150.0); [btn setImage:[self scaleAndRotateImage:[UIImage imageNamed:@"basicbutton.png"]] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; //add "stuff" to scrolling area [scrollView addSubview:rowsBackground]; [scrollView addSubview:btn]; //add scrolling area to cocos2d //this is just a UIWindow [[[Director sharedDirector] openGLView] addSubview:scrollView]; //mem-mgmt [rowsBackground release]; [btn release]; [scrollView release]; 

Чтобы UIScrollView определял разницу между кликом, который проходит до его содержимого (ов) и касанием, которое превращается в салфетки или щепотку, необходимо затянуть прикосновение и посмотреть, был ли ваш палец перемещен во время этой задержки. Установив delaysContentTouches в NO в вашем примере выше, вы предотвратите это. Таким образом, просмотр прокрутки всегда передает касание к кнопке, вместо того, чтобы отменить ее, когда выясняется, что пользователь выполняет жестовый салфет. Попробуйте установить delaysContentTouches на YES .

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

Решение, которое сработало для меня, включало:

  1. Настройка canCancelContentTouches в UIScrollView на YES .
  2. Расширение UIScrollView для переопределения touchesShouldCancelInContentView:(UIView *)view для возврата YES когда view является UIButton .

В соответствии с документацией touchesShouldCancelInContentView возвращает « YES чтобы отменить дальнейшие сенсорные сообщения для просмотра, NO чтобы иметь возможность продолжать просмотр этих сообщений. Возвращаемое по умолчанию значение равно YES если view не является объектом UIControl , в противном случае он возвращает NO ».

Поскольку UIButton является UIControl расширение необходимо для получения canCancelContentTouches для вступления в силу, что позволяет прокручивать.

У меня есть аналогичный случай, когда несколько кнопок на UIScrollView, и я хочу прокрутить эти кнопки. Сначала я подclassифицировал UIScrollView и UIButton. Тем не менее, я заметил, что мой подclassовый UIScrollView не получил событие touchesEnded, поэтому я изменил только на подclass UIButton.

 @interface MyPhotoButton : UIButton { } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; @end 
 @implementation MyPhotoButton - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; [self setEnabled:NO]; [self setSelected:NO]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self setEnabled:YES]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; [self setEnabled:YES]; } @end 

UIScrollView обрабатывает множество событий. Вам необходимо обрабатывать touchhesDidEnd и удалять тест для кнопок внутри UIScrollView вручную.

Хорошо, вот ваш ответ:

Подclass UIButton. (ПРИМЕЧАНИЕ: вызовите [super ….] в начале каждого переопределения.

  • Добавьте свойство. Один из типов BOOL (называемый enableToRestore)
  • Добавьте свойство. Один из типов CGPoint (называемый startTouchPosition)
  • в awakeFromNib и initWithFrame установите для свойства enableToRestore свойство isEnabled)
  • Переопределить «touchesBegan: withEvent:», чтобы сохранить начало позиции касания.
  • Переопределить «touchesMoved: withEvent:», чтобы проверить, есть ли горизонтальное перемещение.
  • Если ДА, установите значение НЕТ и выбрано значение НЕТ.

Образец кода:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; [super touchesBegan:touches withEvent:event]; [self setStartTouchPosition:[touch locationInView:self]]; } // // Helper Function // - (BOOL)isTouchMovingHorizontally:(UITouch *)touch { CGPoint currentTouchPosition = [touch locationInView:self]; BOOL rValue = NO; if (fabsf([self startTouchPosition].x - currentTouchPosition.x) >= 2.0) { rValue = YES; } return (rValue); } // // This is called when the finger is moved. If the result is a left or right // movement, the button will disable resulting in the UIScrollView being the // next responder. The parrent ScrollView will then re-enable the button // when the finger event is ended of cancelled. // - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; if ([self isTouchMovingHorizontally:[touches anyObject]]) { [self setEnabled:NO]; [self setSelected:NO]; } } 

Это активирует UIScrollView.

Подclass UIScrollView. (ПРИМЕЧАНИЕ: вызовите [super ….] в начале каждого переопределения.

  • Переопределите оба параметра «touchesEnded: withEvent:» и «touchsCancelled: withEvent:»
  • В переопределении сбросьте все флажки с включенным подпунктом (и их дочерними элементами).
  • ПРИМЕЧАНИЕ. Используйте категорию и добавьте метод в UIView:

,

 - (void) restoreAllEnables { NSArray *views = [self subviews]; for (UIView *aView in views) { if ([aView respondsToSelector:@selector(restoreEnable)]) { [aView restoreEnable]; } } } - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self restoreAllEnables]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self restoreAllEnables]; } 
  • В категории:

,

 -(void) restoreEnable { NSArray *views = [self subviews]; if ([self respondsToSelector:@selector(enableToRestore)]) { [self setEnabled:[self enableToRestore]]; } for (UIView *aView in views) { if ([aView respondsToSelector:@selector(restoreEnable)]) { [aView restoreEnable]; } } } 

EDIT Примечание. Я никогда не получал ответ 3 на работу. Аналогично: setDelaysContentTouches: NO (установленный в controllerе представления или где-нибудь) должен быть установлен для получения наилучших результатов в ответе 4. Это обеспечивает очень быструю реакцию на кнопки. Настройка setDelaysContentTouches: YES оказывает серьезное влияние (150 мс) на время отклика на кнопки и делает свет, быстрое касание невозможным.

Другой способ:
1. Замените кнопку простым пользовательским UIView
2. Поместите флаг «userInterationEnable = yes;» по методу init
3. В представлении override метод UIResponder «touchesEnded» здесь вы можете вызвать действие, которое вам нужно, как кнопку.

По моему опыту первый ответ, т. delaysContentTouches Просто установление delaysContentTouches на YES , ничего не меняет в отношении проблемы. Кнопки все равно не передадут результаты отслеживания в режим прокрутки. Третий ответ прост и очень полезен. Спасибо sieroaoj!

Тем не менее, для третьего ответа на работу вам также потребуются delaysContentTouches установлен на YES . В противном случае метод touchesEnded также будет вызван для отслеживания в представлении. Поэтому я мог бы решить проблему:

  1. Замените кнопку простым пользовательским UIView
  2. Поместите флаг «userInterationEnable = yes;» по методу init
  3. В представлении override метод UIResponder «touchesEnded» здесь вы можете инициировать действие, которое вы

В-четвертых. set delaysContentTouches to YES

  • Безопасность NSMutableDictionary
  • Каковы детали «Objective-C Literals», упомянутые в примечаниях к выпуску Xcode 4.4?
  • как предотвратить добавление NSJSONSerialization дополнительных экранов в URL-адрес
  • objective C: что такое «(id) отправитель»?
  • IOS 6: ориентация устройства на пейзаж
  • «FOUNDATION_EXPORT» и «extern»
  • Почему переименовать синтезированные свойства в iOS с ведущими подчеркиваниями?
  • Каков наилучший способ решения конфликта объектов Objective-C?
  • Как добавить subview с собственным UIViewController в Objective-C?
  • Как сохранить пользовательские объекты в NSUserDefaults
  • Xcode 6 и Embedded Frameworks поддерживаются только в iOS8
  • Давайте будем гением компьютера.