UIScrollview с UIButtons – как воссоздать трамплин?
Я пытаюсь создать в моем приложении подобный трамплину интерфейс. Я пытаюсь использовать UIButtons, добавленные в UIScrollView. Проблема, с которой я столкнулся, – это кнопки, не передающие какие-либо штрихи в UIScrollView – если я попытаюсь щелкнуть / сдвинуть и нажимать на кнопку, которую он не регистрирует для UIScrollView, но если я прокручу пробел между кнопок он будет работать. Кнопки нажимают / работают, если я прикасаюсь к ним.
Есть ли свойство или параметр, который заставляет кнопку отправлять события касания до своего родителя (супервизор)? Нужно ли добавлять кнопки к чему-то еще, прежде чем добавлять UIScrollView?
Вот мой код:
- Условно начать в разных местах в раскадровке из AppDelegate
- objective C Интроспекция / reflection
- Как перебирать NSArray?
- Верхние индексы в атрибутной строке
- Как объявить двухмерный массив типа string в Objective-C?
//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];
- Объективные переменные уровня статического classа
- Каким должен быть мой объектив-C-сингл?
- Получить общее количество шагов для каждой даты в HealthKit
- Использование NSString в операторе switch
- Индекс символов в точке касания для UILabel
- Как я могу сделать свое шифрование AES идентичным между Java и Objective-C (iPhone)?
- Как можно маскировать UIImageView?
- недопустимый контекст 0x0 под iOS 7.0 и деgradleация системы
Чтобы UIScrollView
определял разницу между кликом, который проходит до его содержимого (ов) и касанием, которое превращается в салфетки или щепотку, необходимо затянуть прикосновение и посмотреть, был ли ваш палец перемещен во время этой задержки. Установив delaysContentTouches
в NO
в вашем примере выше, вы предотвратите это. Таким образом, просмотр прокрутки всегда передает касание к кнопке, вместо того, чтобы отменить ее, когда выясняется, что пользователь выполняет жестовый салфет. Попробуйте установить delaysContentTouches
на YES
.
Также может быть хорошей идеей, структурно, добавить все представления, которые будут размещены в вашем представлении прокрутки, к общему представлению контента и использовать только это представление в качестве подсмотра представления прокрутки.
Решение, которое сработало для меня, включало:
- Настройка
canCancelContentTouches
вUIScrollView
наYES
. - Расширение
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
также будет вызван для отслеживания в представлении. Поэтому я мог бы решить проблему:
- Замените кнопку простым пользовательским UIView
- Поместите флаг «userInterationEnable = yes;» по методу init
- В представлении override метод UIResponder «touchesEnded» здесь вы можете инициировать действие, которое вы
В-четвертых. set delaysContentTouches
to YES