iOS - отложенное событие "Touch Down" для UIButton в UITableViewCell

У меня есть пользовательский UITableViewCell, который инициализируется следующим:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        self = [nibArray objectAtIndex:0];

        [self setSelectionStyle:UITableViewCellSelectionStyleNone];

        [self.downButton setBackgroundImage:[UIImage imageNamed:@"button"] forState:UIControlStateNormal];
        [self.downButton setBackgroundImage:[UIImage imageNamed:@"buttonSelected"] forState:UIControlStateHighlighted];
    }
    return self;
}

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

Пытаясь смягчить запоздалое изменение при переключении на выделенное изображение, я поместил изменение следующим способом:

- (IBAction)downDown:(id)sender {
    [self.downButton setBackgroundColor:[UIColor redColor]];
}

Метод выше установлен для "Touch Down" (в отличие от более распространенного "Touch Up Inside"), и я удалил setBackgroundImage:forState: для выделенного состояния. Та же проблема, что и выше. Цвет в конечном итоге изменится на красный, но только после нажатия и удержания кнопки в течение секунды или двух.

У меня есть метод для кнопки, которая вызывается, когда происходит "Touch Up Inside", и этот метод выполняется без проблем - независимо от того, быстро ли я нажимаю кнопку или нажимаю и удерживаю ее в течение некоторого времени, прежде чем отпустить.

Так почему задержка для "Touch Down" или UIControlStateHighlighted? Я пытаюсь предоставить мгновенный отзыв пользователю, чтобы показать, что кнопка была нажата.

Я могу предоставить больше кода, если это необходимо, но это единственные фрагменты, которые имеют отношение к фоновому оформлению.

7 ответов

Решение

Это вызвано UIScrollView имущество delaysContentTouches,

Раньше было достаточно просто установить это свойство NO для UITableView само по себе, но это будет работать только для подпредставлений таблицы, которые не заключены в другой UIScrollView,

UITableViewCells содержат внутренний вид прокрутки в iOS 7, поэтому вам нужно будет изменить значение этого свойства на уровне ячеек для всех ячеек с кнопками в них.

Вот что вам нужно сделать:

1.in viewDidLoad или где-то похожий, когда ваш UITableView был инициализирован, поместите это в:

self.tableView.delaysContentTouches = NO;

2. для поддержки iOS 7, в методе инициализации для вашего UITableViewCell (initWithStyle:reuseIdentifier: или же initWithCoder: для NIB), поместите это в конце:

for (UIView *currentView in self.subviews)
{
    if([currentView isKindOfClass:[UIScrollView class]])
    {
        ((UIScrollView *)currentView).delaysContentTouches = NO;
        break;
    }
}

К сожалению, это не на 100% постоянное решение, так как Apple может снова изменить иерархию представлений внутри ячеек в будущем (возможно, переместить представление прокрутки на другой слой вниз или что-то, что потребует от вас вложения еще одного цикла), но до тех пор, пока они не появятся на поверхности. класс или, по крайней мере, собственность для разработчиков, это лучшее, что у нас есть.

РешениеSwift 3 (для iOS8+):

Во-первых, отключите задержки в UITableView после того, как он успешно загружен, например, внутри viewDidLoad() метод:

someTableView.delaysContentTouches = false

Затем отключите задержки в видах прокрутки, содержащихся внутри UITableView:

for case let scrollView as UIScrollView in someTableView.subviews {
    scrollView.delaysContentTouches = false
}

Примечание для iOS7: возможно, вам придется отключить задержки в UITableViewCell, (Проверьте ответ Димы).

Вы также можете найти другие советы здесь.

Я решаю эту проблему в своем коде путем создания подклассов UIButton,

Цель С

@interface TBButton : UIButton

@end

@implementation TBButton

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.highlighted = true;
    [super touchesBegan:touches withEvent:event];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.highlighted = false;
    [super touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.highlighted = false;
    [super touchesCancelled:touches withEvent:event];
}

@end

быстрый

class TBButton: UIButton {
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        highlighted = true
        super.touchesBegan(touches, withEvent: event)
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        highlighted = false
        super.touchesEnded(touches, withEvent: event)
    }
    override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
        highlighted = false
        super.touchesCancelled(touches, withEvent: event)
    }
}

Свифт 3

class TBButton: UIButton {
    override func touchesBegan(_ touches: Set<UITouch>, with event:     UIEvent?) {
        isHighlighted = true
        super.touchesBegan(touches, with: event)
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event:     UIEvent?) {
        isHighlighted = false
        super.touchesEnded(touches, with: event)
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        isHighlighted = false
        super.touchesCancelled(touches, with: event)
    }
}

Свифт 3 версия ответа Alex:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    isHighlighted = true
    super.touchesBegan(touches, with: event)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    isHighlighted = false
    super.touchesEnded(touches, with: event)
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    isHighlighted = false
    super.touchesCancelled(touches, with: event)
}

Вот рекурсивное решение, которое вы можете добавить в свой контроллер представления:

+ (void)disableDelayedTouches:(UIView*)view
{
    for(UIView *currentView in view.subviews) {
        if([currentView isKindOfClass:[UIScrollView class]]) {
            ((UIScrollView *)currentView).delaysContentTouches = NO;
        }
        [self disableDelayedTouches:currentView];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.class disableDelayedTouches:self.view];
}

Так почему задержка для "Touch Down" или UIControlStateHighlighted? Я пытаюсь предоставить мгновенный отзыв пользователю, чтобы показать, что кнопка была нажата.

Apple еще не объяснила это?

Без этой задержки:

  1. Если вы хотите прокрутить представление, и ваш палец касается чего-нибудь выделяемого (например, любой ячейки таблицы со стилем выделения по умолчанию), вы получите следующие мигающие артефакты:

    введите описание изображения здесь

    На самом деле, они не знают о touchDown, собираетесь ли вы нажать или прокрутить.

  2. Если вы хотите прокрутить вид, и ваш палец касается UIButton/UITextFieldвид не прокручивается вообще! Поведение Button/TextField по умолчанию "сильнее", чем поведение прокрутки, оно продолжает ждать touchUpInside событие.

Может быть, этот ответ более прост. просто добавьте задержку анимации. как ниже:

    [self.publishButton bk_addEventHandler:^(id sender) {
    @strongify(self);
    // reset to normal state with delay
    [UIView animateWithDuration:0.1 animations:^{
        self.publishButton.backgroundColor = [UIColor whiteColor];
    }];
    } forControlEvents:UIControlEventTouchUpInside];

   [self.publishButton bk_addEventHandler:^(id sender) {
    //Set your Image or color
       self.publishButton.backgroundColor = [UIColor redColor];
   } forControlEvents:UIControlEventTouchDown];
Другие вопросы по тегам