UIScrollview с UIButtons - как воссоздать трамплин? - PullRequest
34 голосов
/ 16 марта 2009

Я пытаюсь создать подобный трамплину интерфейс в моем приложении. Я пытаюсь использовать кнопки UIB, добавленные в 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];

Ответы [ 7 ]

44 голосов
/ 04 августа 2010

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

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

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

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

28 голосов
/ 18 марта 2009

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

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

5 голосов
/ 27 апреля 2010

У меня похожий случай с количеством кнопок на 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
1 голос
/ 26 февраля 2010

ОК, вот ваш ответ:

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

  • Добавить недвижимость. Один из типа BOOL (называется enableToRestore)
  • Добавить недвижимость. Один из типа CGPoint (называется startTouchPosition)
  • в пробуждении от Nib и initWithFrame, установите enableToRestore для isEnabled свойство)
  • Переопределить "touchSegan: 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];
        }
    }
}

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

1 голос
/ 16 марта 2009

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

0 голосов
/ 11 ноября 2009

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

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

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

В-четвертых. установите delaysContentTouches в YES

0 голосов
/ 30 мая 2009

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

...