34

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

Есть ли свойство или настройка, которая заставляет кнопку отправлять события касания до своего родителя (супервизора)? Нужно ли добавлять кнопки к чему-то еще, прежде чем добавлять 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]; 
+0

Следует отметить, что, несмотря на то, Apple, позволило раньше, '10.4' ' приложения, которые создают другое окружение рабочего стола/домашний экран или имитирующие мульти-App опыт виджет будет rejected'. На всякий случай некоторые новички планировали отправить производственное приложение с собственным трамплином. – user

ответ

28

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

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

+3

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

+0

Совет по дизайну является удивительным, но мне было бы интересно, почему. Благодарю. –

1

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

0

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

0

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

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

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

Четвертую. установить delaysContentTouches в YES

+0

Задержки-задержкиContentTouches = YES по умолчанию. – Andy

1

OK вот ваш ответ:

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

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

Пример кода:

- (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. (Примечание: вызов [супер ....] в начале каждого переопределения

  • Override как "touchesEnded: withEvent:". И "touchesCancelled: 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 (установленный в контроллере вида или в каком-либо месте) должен быть установлен для получения наилучших результатов в ответ 4. Это обеспечивает очень быструю реакцию на кнопки. Настройка setDelaysContentTouches: YES оказывает серьезное влияние (150 мс) на время отклика на кнопки и делает свет, быстрое касание невозможным.

5

У меня есть аналогичный случай, что несколько кнопок на 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 
+0

Это решение отлично сработало для меня. – GroovyCarrot

44

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

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

Согласно документации touchesShouldCancelInContentView возвращается "YES отменить дополнительные сенсорные сообщения для просмотра, NO иметь вид продолжает получать эти сообщения по умолчанию возвращается значение YES, если вид не UIControl объекта, в противном случае она возвращает NO «.

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

+8

Большое спасибо! Чтобы прояснить это, это работает лучше всего, когда delay.ContentTouches = NO. – Schrockwell

+7

Это путь! (по крайней мере, для iOS 4+), я нашел, что наиболее универсально переопределить вот так: '- (BOOL) touchsShouldCancelInContentView: (UIView *) view { return! [view isKindOfClass: [UISlider class]]; } ' –

+0

Все еще отлично работает в iOS 7. Большое спасибо! – RyanG

Смежные вопросы