71

我看过很多关于类似事情的帖子,但没有一个能完全匹配或解决这个问题。从 iOS 7 开始,每当我将 a 添加UIButton到 aUITableViewCell甚至添加到 footerview 时,它都会“正常”工作,这意味着它会接收目标操作,但它不会显示通常在您点击 a 时发生的小亮点UIButton。它使 UI 看起来很时髦,没有显示按钮对触摸的反应。

我很确定这算作 iOS7 中的一个错误,但有没有人找到解决方案或可以帮助我找到一个解决方案:)

编辑:我忘了提到如果我长时间按住按钮它会突出显示,但不会像刚刚添加到标准视图那样快速点击。

代码:

创建按钮:

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.titleLabel.font = [UIFont systemFontOfSize:14];
    button.titleLabel.textColor = [UIColor blueColor];
    [button setTitle:@"Testing" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(buttonPressed:) forControlEvents: UIControlEventTouchDown];
    button.frame = CGRectMake(0, 0, self.view.frame.size.width/2, 40);

我测试过的东西:

//移除手势识别器UITableView,以防它们碍事。

for (UIGestureRecognizer *recognizer in self.tableView.gestureRecognizers) {
   recognizer.enabled = NO;
}

//从单元格中移除手势

for (UIGestureRecognizer *recognizer in self.contentView.gestureRecognizers) {
       recognizer.enabled = NO;
    }

//这显示了轻微的触摸,但这不是所需的外观

button.showsTouchWhenHighlighted = YES;
4

17 回答 17

92

在该表视图中,您只需添加此属性。

tableview.delaysContentTouches = NO;

并在启动单元格后添加 cellForRowAtIndexPath ,然后在下面的代码中添加。单元格的结构在 iOS 6 和 iOS 7 中明显不同
。iOS 7 我们有一个控件 UITableViewCellScrollView 在 UITableViewCell 和内容视图之间。

for (id obj in cell.subviews)
{
    if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"])
    {
        UIScrollView *scroll = (UIScrollView *) obj;
        scroll.delaysContentTouches = NO;
        break;
    }
}
于 2013-10-10T15:03:59.710 回答
40

从 iOS 8 开始,我们需要对 UITableView 子视图应用相同的技术(表包含隐藏的 UITableViewWrapperView 滚动视图)。不再需要迭代 UITableViewCell 子视图。

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

这个答案应该与这个问题联系起来。

于 2014-07-10T00:15:30.773 回答
27

我试图将此添加到已接受的答案中,但从未通过。这是关闭单元格 delaysContentTouches 属性的更安全的方法,因为它不查找特定的类,而是任何响应选择器的内容。

在单元格中:

for (id obj in self.subviews) {
     if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]) {
          [obj setDelaysContentTouches:NO];
     }
}

在表视图中:

self.tableView.delaysContentTouches = NO;
于 2013-10-29T23:31:40.490 回答
18

对于同时适用于 iOS7 和 iOS8 的解决方案,请创建自定义UITableView子类和自定义UITableViewCell子类。

使用这个样本UITableViewinitWithFrame:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if (self)
    {
        // iterate over all the UITableView's subviews
        for (id view in self.subviews)
        {
            // looking for a UITableViewWrapperView
            if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"])
            {
                // this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
                if([view isKindOfClass:[UIScrollView class]])
                {
                    // turn OFF delaysContentTouches in the hidden subview
                    UIScrollView *scroll = (UIScrollView *) view;
                    scroll.delaysContentTouches = NO;
                }
                break;
            }
        }
    }
    return self;
}

使用这个样本UITableViewCellinitWithStyle:reuseIdentifier:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self)
    {
        // iterate over all the UITableViewCell's subviews
        for (id view in self.subviews)
        {
            // looking for a UITableViewCellScrollView
            if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewCellScrollView"])
            {
                // this test is here for safety only, also there is no UITableViewCellScrollView in iOS8
                if([view isKindOfClass:[UIScrollView class]])
                {
                    // turn OFF delaysContentTouches in the hidden subview
                    UIScrollView *scroll = (UIScrollView *) view;
                    scroll.delaysContentTouches = NO;
                }
                break;
            }
        }
    }

    return self;
}
于 2014-09-25T22:31:52.727 回答
17

我为解决该问题所做的是使用以下代码的 UIButton 类别:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];


    [NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = YES; }];
}


- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];

    [self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];

    [self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1];
}


- (void)setDefault
{
    [NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = NO; }];
}

当我在 UITableViewCell 中按下按钮时,按钮会正确反应,并且我的 UITableView 行为正常,因为delaysContentTouches没有强制。

于 2014-07-04T12:21:30.790 回答
11

这是 Roman B 在 Swift 2 中的回答:

for view in tableView.subviews {
    if view is UIScrollView {
        (view as? UIScrollView)!.delaysContentTouches = false
        break
    }
}
于 2016-02-19T05:43:14.933 回答
5
    - (void)viewDidLoad
{

    [super viewDidLoad];


    for (id view in self.tableView.subviews)
    {
        // looking for a UITableViewWrapperView
        if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"])
        {
            // this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
            if([view isKindOfClass:[UIScrollView class]])
            {
                // turn OFF delaysContentTouches in the hidden subview
                UIScrollView *scroll = (UIScrollView *) view;
                scroll.delaysContentTouches = NO;
            }
            break;
        }
    }
}

在此处输入图像描述

于 2014-12-11T07:36:39.017 回答
5

我在 UITableViewCell 中的纯文本 UIButton 遇到类似的问题,在触摸时未突出显示。为我解决的问题是将按钮类型从自定义更改回系统。

将 delaysContentTouches 设置为 NO 对同一 UITableViewCell 中的仅图像 UIButton 起到了作用。

self.tableView.delaysContentTouches = NO;

在此处输入图像描述

于 2015-07-22T15:13:37.167 回答
4

这是上面 Raphaël Pinto 答案的Swift版本。别忘了也给他点个赞:)

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    super.touchesBegan(touches, withEvent: event)
    NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = true }
}

override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
    super.touchesCancelled(touches, withEvent: event)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue()) {
        self.setDefault()
    }
}

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
    super.touchesEnded(touches, withEvent: event)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue()) {
        self.setDefault()
    }
}

func setDefault() {
    NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = false }
}
于 2015-01-21T11:33:57.190 回答
3

Swift 中的解决方案,仅限 iOS8(需要对 iOS7 的每个单元进行额外的工作):

//
//  NoDelayTableView.swift
//  DivineBiblePhone
//
//  Created by Chris Hulbert on 30/03/2015.
//  Copyright (c) 2015 Chris Hulbert. All rights reserved.
//
//  This solves the delayed-tap issue on buttons on cells.

import UIKit

class NoDelayTableView: UITableView {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        delaysContentTouches = false

        // This solves the iOS8 delayed-tap issue.
        // http://stackoverflow.com/questions/19256996/uibutton-not-showing-highlight-on-tap-in-ios7
        for view in subviews {
            if let scroll = view as? UIScrollView {
                scroll.delaysContentTouches = false
            }
        }
    }

    override func touchesShouldCancelInContentView(view: UIView!) -> Bool {
        // So that if you tap and drag, it cancels the tap.
        return true
    }

}

要使用,您只需将类更改为NoDelayTableView故事板中的类即可。

我可以确认在 iOS8 中,放置在单元格中 contentView 内的按钮现在会立即突出显示。

于 2015-03-30T11:17:36.917 回答
2

克里斯哈里森答案的略微修改版本。斯威夫特 2.3:

class HighlightButton: UIButton {
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        super.touchesBegan(touches, withEvent: event)
        NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = true }
    }

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

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

    private func setDefault() {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
            NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = false }
        }
    }
}
于 2016-10-15T18:21:24.763 回答
1

接受的答案对我来说在某些“水龙头”上不起作用。

最后,我在 uibutton 类别(/子类)中添加了波纹管代码,它百分百有效。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

self.backgroundColor = [UIColor greenColor];
[UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    self.backgroundColor = [UIColor clearColor];

} completion:^(BOOL finished)
 {
 }];
[super touchesBegan:touches withEvent:event];

}
于 2014-02-28T11:29:58.790 回答
0

我写了一个类别扩展UITableViewCell来使这个问题易于解决。它与接受的答案基本相同,除了我从UITableViewCell contentView.

我考虑了一个完全“自动”的解决方案,它可以使添加到UITableView集合中的所有单元格的delaysContentTouches状态与拥有UITableView的状态相匹配delaysContentTouches。为了完成这项工作,我必须要么 swizzle UITableView,要么要求开发人员使用UITableView子类。我不想要求任何我都选择了这个我觉得更简单、更灵活的解决方案。

类别扩展和示例线束在这里:

https://github.com/TomSwift/UITableViewCell-TS_delaysContentTouches

使用起来非常简单:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // using static cells from storyboard...
    UITableViewCell* cell = [super tableView: tableView cellForRowAtIndexPath: indexPath];

    cell.ts_delaysContentTouches = NO;

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

这是该类别的代码:

@interface UITableViewCell (TS_delaysContentTouches)

@property (nonatomic, assign) BOOL ts_delaysContentTouches;

@end

@implementation UITableViewCell (TS_delaysContentTouches)

- (UIScrollView*) ts_scrollView
{
    id sv = self.contentView.superview;
    while ( ![sv isKindOfClass: [UIScrollView class]] && sv != self )
    {
        sv = [sv superview];
    }

    return sv == self ? nil : sv;
}

- (void) setTs_delaysContentTouches:(BOOL)delaysContentTouches
{
    [self willChangeValueForKey: @"ts_delaysContentTouches"];

    [[self ts_scrollView] setDelaysContentTouches: delaysContentTouches];

    [self didChangeValueForKey: @"ts_delaysContentTouches"];
}

- (BOOL) ts_delaysContentTouches
{
    return [[self ts_scrollView] delaysContentTouches];
}

@end
于 2014-01-31T18:43:39.410 回答
0

由于 objc 是动态的,并且 scrollView 是唯一响应 delaysContentTouches 的类,因此这应该适用于 ios 7 和 8(将它放在 tableViewController 的早期位置,例如 awakeFromNib):

for (id view in self.tableView.subviews)
    {
        if ([view respondsToSelector:@selector(delaysContentTouches)]) {
            UIScrollView *scrollView = (UIScrollView *)view;
            scrollView.delaysContentTouches = NO;
            break;
        }
}

您可能还必须通过选择 viewController 中的表格来关闭情节提要或 nib 中的“delaysContentTouches”。顺便说一句,如果您在 viewController 中使用 tableView,这可能不适用于 ios 7,至少我无法让它工作。

于 2015-03-09T18:20:58.170 回答
0

那个解决方案对我不起作用,我修复了 TableView 的子类化并实现了这两种方法

- (instancetype)initWithCoder:(NSCoder *)coder{
   self = [super initWithCoder:coder];
   if (self) {
     for (id obj in self.subviews) {
      if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]){
            [obj performSelector:@selector(setDelaysContentTouches:) withObject:NO];
      }
     }
   }
   return self;
}

- (BOOL)delaysContentTouches{
   return NO;
}
于 2015-03-25T15:21:02.890 回答
0

适用于 iOS 7 和 8 的 Swift 解决方案:

首先我写了一个实用函数:

class func classNameAsString(obj: AnyObject) -> String {
    return _stdlib_getDemangledTypeName(obj).componentsSeparatedByString(".").last!
}

然后我继承 UITableView 并实现这个:

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    for view in self.subviews {
        if (Utility.classNameAsString(view) == "UITableViewWrapperView") {
            if view.isKindOfClass(UIScrollView) {
                var scroll = (view as UIScrollView)
                scroll.delaysContentTouches = false
            }
            break
        }
    }
}

我还继承了 UITableViewCell 并实现了这个:

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    for view in self.subviews {
        if (Utility.classNameAsString(view) == "UITableViewCellScrollView") {
            if view.isKindOfClass(UIScrollView) {
                var scroll = (view as UIScrollView)
                scroll.delaysContentTouches = false
            }

        }
    }
}

在我的情况下, init(coder:) 将运行。请在您的 init 函数中放置调试点以了解哪个 init 函数将运行,然后使用上面的代码使其工作。希望能帮助到某人。

于 2015-05-12T08:06:49.083 回答
0

在 Swift 3 中,这个 UIView 扩展可以在 UITableViewCell 上使用。最好在cellForRowAt方法中。

func removeTouchDelayForSubviews() {
    for subview in subviews {
        if let scrollView = subview as? UIScrollView {
            scrollView.delaysContentTouches = false
        } else {
            subview.removeTouchDelayForSubviews()
        }
    }
}
于 2017-03-15T16:11:01.820 回答