UIScrollView с UIButtons - как воссоздать springboard?
-
19-08-2019 - |
Вопрос
Я пытаюсь создать интерфейс, похожий на springboard, в своем приложении.Я пытаюсь использовать UIButtons, добавленные в UIScrollView.Проблема, с которой я сталкиваюсь, заключается в том, что кнопки не передают никаких касаний в UIScrollView - если я попытаюсь щелкнуть / сдвинуть и случайно нажму на кнопку, это не зарегистрируется в UIScrollView, но если я щелкну пробелом между кнопками, это сработает.Кнопки действительно щелкают / работают, если я к ним прикасаюсь.
Существует ли свойство или настройка, которая заставляет кнопку отправлять события касания своему родительскому элементу (superview)?Нужно ли добавлять кнопки к чему-то еще перед добавлением 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
в приведенном выше примере, вы не допустите этого. Поэтому представление прокрутки всегда передает касание кнопке, а не отменяет его, когда оказывается, что пользователь выполняет жест смахивания. Попробуйте установить YES
на <=>.
Структурно также может быть хорошей идеей добавить все представления, которые будут размещены в представлении прокрутки, в общее представление содержимого и использовать только это представление в качестве подпредставления представления прокрутки.
Другие советы
Решение, которое работало для меня, включало:
<Ол>canCancelContentTouches
в UIScrollView
значение YES
. touchesShouldCancelInContentView:(UIView *)view
для переопределения view
для возврата UIButton
, когда touchesShouldCancelInContentView
является NO
. Согласно документации UIControl
возвращает " <=>, чтобы отменить дальнейшие сенсорные сообщения для просмотра, <=> чтобы просмотр продолжал получать эти сообщения. Возвращаемым значением по умолчанию является <=>, если представление не является объектом <=>; в противном случае возвращается <=>. "
Поскольку <=> является <=>, для вступления в силу <=> необходимо расширение, которое позволяет прокручивать. Р>
У меня есть похожий случай с несколькими кнопками на UIScrollView, и я хочу прокрутить эти кнопки. В начале я вложил в подклассы UIScrollView и UIButton. Однако я заметил, что мой подкласс UIScrollView не получил событие touchesEnded, поэтому я переключился только на подкласс 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 сам обрабатывает множество событий. Вам нужно вручную обработать touchesDidEnd и выполнить проверку нажатия кнопок внутри UIScrollView.
Хорошо, вот ваш ответ:
Подкласс 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.
Подкласс UIScrollView.(ПРИМЕЧАНИЕ:вызывайте [super ....] в начале каждого переопределения.
- Переопределить оба "касания":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];
}
}
}
Редактировать Примечание:Я так и не добился, чтобы ответ 3 сработал.Аналогично:setDelaysContentTouches: NO (заданный в контроллере представления или где-либо еще) должен быть установлен для достижения наилучших результатов в ответе 4.Это обеспечивает очень быструю реакцию на кнопки.Настройка setDelaysContentTouches: ДА оказывает серьезное влияние (150 мс) на время отклика кнопок и делает невозможным легкое и быстрое нажатие.
Другой способ:
1. Замените кнопку de простым пользовательским UIView
2. Поставьте флаг & Quot; userIntivationEnable = yes; & Quot; на метод init
3. В представлении переопределите метод UIResponder " touchesEnded " здесь вы можете запустить нужное вам действие, например кнопку.
По моему опыту, первый ответ, т.е. простая настройка delaysContentTouches
Для YES
, ничего не меняет в отношении проблемы.Кнопки по-прежнему не будут отображать результаты отслеживания в режиме прокрутки.Третий ответ одновременно прост и очень полезен.Спасибо, сероаой!
Однако для того, чтобы третий ответ сработал, вам также необходимо delaysContentTouches
установлено значение YES
.В противном случае метод touchesEnded
также будет вызван для отслеживания в рамках представления.Поэтому я мог бы решить проблему следующим образом:
- Замените кнопку de простым пользовательским UIView
- Установите флаг "userInterationEnable = yes;" в методе init
- В представлении переопределите метод UIResponder "touchesEnded" здесь вы можете запустить действие, которое вам нужно
Четвертый.установленный delaysContentTouches
Для YES