Вопрос

Я пытаюсь создать интерфейс, похожий на 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 также будет вызван для отслеживания в рамках представления.Поэтому я мог бы решить проблему следующим образом:

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

    Четвертый.установленный delaysContentTouches Для YES

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top