【问题标题】:iOS - Delayed "Touch Down" event for UIButton in UITableViewCelliOS - UITableViewCell 中 UIButton 的延迟“Touch Down”事件
【发布时间】:2014-05-20 10:16:15
【问题描述】:

我有一个自定义的 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?我正在尝试向用户提供即时反馈,以表明该按钮已被按下。

如果需要,我可以提供更多代码,但这些是唯一与背景外观有关的部分。

【问题讨论】:

  • 我想说这是因为图像没有预先加载,但显然这不适用于彩色情况。当你不创建自己的并使用 Xcode 的故事板来生成按钮时,它会有所不同吗?
  • 同样的交易。如果我在情节提要编辑器中定义背景图像/颜色,按钮仍然需要用户按住一段时间才能发生任何更改。
  • 这是奇怪的行为。由于没有人回答这个问题,我建议在谷歌上搜索“objective c touchdown delay”。
  • 那是我看的第一个地方。如果不先与它抗争,我不会在这里发布一些东西。
  • 它在 iOS 9 上对我不起作用

标签: ios objective-c uitableview uibutton


【解决方案1】:

这是由UIScrollView 属性delaysContentTouches 引起的。

对于UITableView 本身,只需将该属性设置为NO 就足够了,但这仅适用于未包含在另一个UIScrollView 中的表的子视图。

UITableViewCells 在 iOS 7 中包含一个内部滚动视图,因此您需要在单元格级别为所有带有按钮的单元格更改此属性的值。

这是你需要做的:

1.在viewDidLoad 或类似的地方,一旦你的UITableView 被初始化,把它放进去:

self.tableView.delaysContentTouches = NO;

2.对于iOS 7支持,在你的UITableViewCellinitWithStyle:reuseIdentifier:initWithCoder:对于NIB)的初始化方法中,把这个放在最后:

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

不幸的是,这不是一个 100% 永久的解决方案,因为 Apple 可以在将来再次更改单元格内的视图层次结构(可能将滚动视图向下移动另一层或需要您在其中嵌套另一个循环的东西),但直到他们以某种方式向开发人员展示了类或至少属性,这是我们所拥有的最好的。

【讨论】:

  • 无需知道单元格滚动视图的确切(私有)类名,只需使用if ([currentView isKindOfClass:[UIScrollView class]]) {...}UIScrollView 的子类也是如此。
  • 完美!我已经为此奋斗了一段时间。一个人如何找到这些问题的具体解决方案!?
  • 这解决了我注意到的一个问题,但还没有坐下来找出解决方案。谢谢
  • 哦,我明白了。我的 initWithStyle 方法没有被调用,因为我的单元格是在 IB 中创建的。我能够使用initWithCoder 作为this answer 提及。
  • @AdamJohns 将此注释添加到我的回答中,以便其他人受益,谢谢。
【解决方案2】:

斯威夫特

首先在UITableView加载成功后关闭延迟,例如viewDidLoad()方法内部:

someTableView.delaysContentTouches = false

然后关闭UITableView中包含的滚动视图中的延迟:

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

iOS7 的注意事项:您可能必须禁用 UITableViewCell 中的延迟。 (检查迪玛的答案)。您还可以找到一些其他提示here

【讨论】:

  • 对我不起作用,我在表格单元格内使用 uitextview,每当我尝试点击其中的链接时就会发生延迟。
  • 很好的答案!第 2 部分是我需要的
  • 第 2 步节省了我的时间!谢谢
【解决方案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)
    }
}

斯威夫特 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)
    }
}

【讨论】:

  • 这应该是公认的答案,因为它对滚动视图没有副作用。
  • 效果很好,除非 TBButton 在 TableViewController 中并且它的操作正在推动另一个 VC。
【解决方案4】:

Swift 3 版本的Alexanswer

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】:

      那么为什么会延迟“着陆”或UIControlStateHighlighted?我正在尝试向用户提供即时反馈,以表明该按钮已被按下。

      苹果还没解释吗?

      没有这个延迟:

      1. 如果您想滚动视图,并且您的手指触摸任何可突出显示的内容(例如,任何具有默认选择样式的表格单元格),您会得到这些闪烁的伪影:

        真的,他们不知道touchDown 是要点击还是滚动。

      2. 如果您想滚动视图,并且您的手指触摸UIButton/UITextField,则视图根本不会滚动! Button/TextField 的默认行为比滚动视图“更强”,它一直在等待 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];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-08
        • 2011-04-23
        • 2016-11-21
        • 1970-01-01
        • 2013-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多