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)
}
}
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 еще не объяснила это?
Без этой задержки:
Если вы хотите прокрутить представление, и ваш палец касается чего-нибудь выделяемого (например, любой ячейки таблицы со стилем выделения по умолчанию), вы получите следующие мигающие артефакты:
На самом деле, они не знают о
touchDown
, собираетесь ли вы нажать или прокрутить.Если вы хотите прокрутить вид, и ваш палец касается
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];