IOS - событие Delayed "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
? Я пытаюсь предоставить мгновенную обратную связь с пользователем, чтобы показать, что кнопка нажата.
Я могу предоставить больше кода, если это необходимо, но это единственные биты, которые имеют какое-либо отношение к внешнему виду.
Ответы
Ответ 1
Это вызвано свойством 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 может снова изменить иерархию представлений внутри ячеек в будущем (возможно, перемещение прокрутки приведет к просмотру другого слоя или к чему-то, что потребует от вас еще одного гнезда), но до тех пор, пока они каким-то образом наследуют класс или, по крайней мере, свойство разработчиков, это лучшее, что у нас есть.
Ответ 2
Решение Swift 3 (для iOS8 +):
Во-первых, отключите задержки в UITableView
после того, как она успешно загружена, например, внутри метода viewDidLoad()
:
someTableView.delaysContentTouches = false
Затем отключите задержки в просмотрах прокрутки, содержащихся внутри UITableView
:
for case let scrollView as UIScrollView in someTableView.subviews {
scrollView.delaysContentTouches = false
}
Примечание для iOS7: вам может потребоваться отключить задержки в UITableViewCell
. (Проверьте ответ Димы).
Вы также можете найти другие советы здесь.
Ответ 3
Я решу эту проблему в своем коде, подклассифицируя UIButton,
Цель C
@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)
}
}
swift 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)
}
}
Ответ 4
версия Swift 3 Alex answer:
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)
}
Ответ 5
Здесь рекурсивное решение, которое вы можете добавить в контроллер вида:
+ (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];
}
Ответ 6
Итак, почему задержка для "Touch Down" или UIControlStateHighlighted
? Я пытаюсь предоставить мгновенную обратную связь с пользователем, чтобы показать, что кнопка нажата.
Разве Apple еще не объяснила это?
Без этой задержки:
-
Если вы хотите прокрутить представление, и ваш палец коснется чего-либо яркого (например, любой ячейки таблицы с стилем выбора по умолчанию), вы получите эти мигающие артефакты:
![введите описание изображения здесь]()
Действительно, они не знают о touchDown
, собираетесь ли вы нажимать или прокручивать.
-
Если вы хотите прокрутить представление, а ваш палец касается UIButton
/UITextField
, вид не прокручивается вообще! Button/TextField по умолчанию "сильнее", чем scrollview, он продолжает ждать события touchUpInside
.
Ответ 7
Возможно, этот ответ более прост. просто добавьте к нему задержку анимации. как показано ниже:
[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];