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];
Ответы
Ответ 1
Чтобы UIScrollView
определить разницу между кликом, который проходит до его содержимого (ов) и прикосновением, которое превращается в салфетки или пинч, необходимо задержать прикосновение и посмотреть, перемещен ли ваш палец во время этой задержки. Установив delaysContentTouches
в NO
в приведенном выше примере, вы предотвращаете это. Таким образом, просмотр прокрутки всегда передает касание к кнопке, вместо того, чтобы отменить ее, когда выясняется, что пользователь выполняет жестовый салфет. Попробуйте установить delaysContentTouches
на YES
.
Также может быть хорошей конструкцией добавить все представления, которые будут размещены в вашем представлении прокрутки, к общему представлению контента и использовать это представление только в качестве представления подпрограммы прокрутки.
Ответ 2
Решение, которое работало для меня, включало:
- Настройка
canCancelContentTouches
в UIScrollView
на YES
.
- Расширение
UIScrollView
для переопределения touchesShouldCancelInContentView:(UIView *)view
для возврата YES
, когда view
является UIButton
.
В соответствии с документацией touchesShouldCancelInContentView
возвращает "YES
, чтобы отменить дальнейшие сенсорные сообщения для просмотра, NO
, чтобы иметь возможность продолжить просмотр этих сообщений. Возвращаемое по умолчанию значение YES
, если представление не является UIControl
объект, в противном случае он возвращает NO
."
Так как UIButton
является UIControl
, расширение необходимо, чтобы получить эффект canCancelContentTouches
, который позволяет прокручивать.
Ответ 3
У меня есть аналогичный случай, когда несколько кнопок на 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
Ответ 4
UIScrollView обрабатывает множество событий. Вам нужно обработать touchhesDidEnd и нажать тест для кнопок внутри UIScrollView вручную.
Ответ 5
ОК, вот ваш ответ:
Подкласс UIButton. (ПРИМЕЧАНИЕ: вызовите [super....] в начале каждого переопределения.
- Добавьте свойство. Один из типов BOOL
(называемый enableToRestore)
- Добавьте свойство. Один из типов CGPoint
(называется startTouchPosition)
- в awakeFromNib и
initWithFrame, установите
enableToRestore к isEnabled
недвижимость)
- Переопределить "touchhesBegan: withEvent:"
сохранить начало прикосновения
положение.
- Переопределить "touchesMoved: withEvent:" to
проверьте, есть ли горизонтальный
движение.
- Если ДА, установите значение НЕТ и
выбрано значение НЕТ.
Пример кода:
- (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....] в начале каждого переопределения.
- Переопределите оба параметра "touchesEnded: withEvent:" и "touchesCancelled: withEvent:"
- В переопределении reset включен флаг всех подзонов (и их дочерних объектов).
- ПРИМЕЧАНИЕ. Используйте категорию и добавьте метод в 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: YES оказывает серьезное воздействие (150 мс) на время отклика на кнопки и делает свет, быстро касаясь, невозможно.
Ответ 6
Другой способ:
1. Замените кнопку простым пользовательским UIView
2. Поместите флаг "userInterationEnable = yes;" по методу init
3. В представлении переопределите метод UIResponder" touchesEnded" здесь, вы можете вызвать действие, которое вам нужно, как кнопку.
Ответ 7
В моем опыте первый ответ, т.е. просто установка delaysContentTouches
в YES
, ничего не меняет в отношении проблемы. Кнопки все равно не передадут результаты отслеживания в режим прокрутки. Третий ответ прост и очень полезен. Спасибо sieroaoj!
Однако для третьего ответа на работу вам также нужно delaysContentTouches
установить YES
. В противном случае метод touchesEnded
также будет вызываться для отслеживания в представлении. Поэтому я мог бы решить проблему:
- Замените кнопку простым пользовательским UIView
- Поместите флаг "userInterationEnable = yes;" по методу init
- В представлении переопределите метод UIResponder "touchesEnded" здесь вы можете вызвать действие, которое вы
В-четвертых. установите delaysContentTouches
в YES