UIButton在iOS7中没有显示突出显示

时间:2013-10-08 19:50:24

标签: iphone ios objective-c uitableview ios7

我看过很多关于类似事情的帖子,但没有一个匹配或解决这个问题。从iOS 7开始,每当我将UIButton添加到UITableViewCell或甚至添加到页脚视图时,它都会“正常”,这意味着它会收到目标操作,但它不显示通常会发生的小亮点当您点按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;
}

//从Cell中删除手势

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

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

button.showsTouchWhenHighlighted = YES;

17 个答案:

答案 0 :(得分:87)

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

tableview.delaysContentTouches = NO;

在启动单元格后添加cellForRowAtIndexPath,只需添加以下代码即可。在iOS 6和iOS 7中,单元的结构明显不同 iOS 7我们在UITableViewCell和内容View之间有一个控件UITableViewCellScrollView。

for (id obj in cell.subviews)
{
    if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"])
    {
        UIScrollView *scroll = (UIScrollView *) obj;
        scroll.delaysContentTouches = NO;
        break;
    }
}

答案 1 :(得分:40)

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

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

This answer应与此问题相关联。

答案 2 :(得分:27)

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

在细胞中:

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

在TableView中:

self.tableView.delaysContentTouches = NO;

答案 3 :(得分:18)

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

使用此示例UITableView' s initWithFrame:

- (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;
}

使用此示例UITableViewCell' s initWithStyle: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;
}

答案 4 :(得分:16)

我为解决问题所做的是使用以下代码的一类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不是强制的。

答案 5 :(得分:10)

这是罗曼B在Swift 2中的答案:

URL in address bar               Effective URL
------------------               -------------
sub.projdomain.com               sub.projdomain.com/myapp/default/index
sub.projdomain.com/              sub.projdomain.com/myapp/default/index
sub.projdomain.com/foo           sub.projdomain.com/myapp/foo/index
sub.projdomain.com/foo?p=1       sub.projdomain.com/myapp/foo/index?p=1
sub.projdomain.com/foo/?p=2      sub.projdomain.com/myapp/foo/index?p=2
sub.projdomain.com/foo/bar?p=3   sub.projdomain.com/myapp/foo/bar?p=3
sub.projdomain.com/foo/bar/?p=4  sub.projdomain.com/myapp/foo/bar?p=4
sub.projdomain.com/a             sub.projdomain.com/admin/default/site

答案 6 :(得分: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;
        }
    }
}

enter image description here

答案 7 :(得分:4)

这是RaphaëlPinto上面回答的 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 }
}

答案 8 :(得分:4)

我在UITableViewCell中遇到与纯文本UIButton类似的问题,而不是在触摸时突出显示。为我修复的是将buttonType从Custom更改回System。

将delaysContentTouches设置为NO对同一UITableViewCell中仅图像的UIButton设置了技巧。

self.tableView.delaysContentTouches = NO;

enter image description here

答案 9 :(得分:3)

仅限iOS8的Swift解决方案(需要为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内的按钮现在可以立即突出显示。

答案 10 :(得分:2)

Chris Harrison's answer的略微修改版本。 Swift 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 }
        }
    }
}

答案 11 :(得分:1)

对于我来说,接受的答案对某些“轻拍”并不起作用。

最后,我在一个uibutton类别(/ subclass)中添加了波纹管代码,它可以百分之百地工作。

- (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];

}

答案 12 :(得分:0)

由于objc是动态的,而scrollView是唯一响应delayedContentTouches的类,这应该适用于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中的表来关闭storyboard或nib中的“delaysContentTouches”。顺便说一下,如果你在viewController中使用tableView,这可能不适用于ios 7,至少我无法让它工作。

答案 13 :(得分: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;
}

答案 14 :(得分: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(编码器:)将运行。请将调试点放在init函数中以了解将运行哪个init函数,然后使用上面的代码使其工作。 希望能帮助别人。

答案 15 :(得分:0)

我在UITableViewCell上写了一个类别扩展名,以简化此问题。除了我从UITableViewCell contentView向上走视图层次结构(而不​​是向下)之外,它与接受的答案基本相同。

我认为这是一个完全“自动化”的解决方案,可以让添加到UITableView的所有单元格设置为delaysContentTouches状态,以匹配拥有UITableView的{​​{1}}状态。为了完成这项工作,我必须调动delaysContentTouches,或要求开发人员使用UITableView子类。我不想要求我解决这个我觉得更简单,更灵活的解决方案。

此处的类别扩展和示例工具:

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

使用起来很简单:

UITableView

以下是该类别的代码:

- (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;
}

答案 16 :(得分:0)

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

func removeTouchDelayForSubviews() {
    for subview in subviews {
        if let scrollView = subview as? UIScrollView {
            scrollView.delaysContentTouches = false
        } else {
            subview.removeTouchDelayForSubviews()
        }
    }
}