UIButton不会在iOS7中显示突出显示

我已经看了很多类似的东西的post,但没有一个相当匹配或解决这个问题。 自iOS 7以来,每当我添加一个UIButton到一个UITableViewCell ,甚至到footerview,它的工作原理是“好的”,这意味着它接收到目标动作,但不会显示通常发生在您点击一个UIButton的小突出显示。 它使界面看起来很时髦,不会显示button对触摸的反应。

我敢肯定,这是iOS7中的一个错误,但任何人都find了解决scheme或可以帮助我find一个:)

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

码:

创buildbutton:

 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); 

我testing过的东西:

//移除UITableView上的手势识别器,以防止它们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; 

在这个tableview中,你只需要添加这个属性。

 tableview.delaysContentTouches = NO; 

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

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

由于iOS 8我们需要将相同的技术应用于UITableView子视图(表中包含隐藏的UITableViewWrapperView滚动视图)。 没有必要迭代UITableViewCell子视图了。

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

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

我试图把这个添加到接受的答案,但它从来没有经过。 这是closures单元格delayedContentTouches属性的更安全的方法,因为它不会查找特定的类,而是任何响应select器的东西。

在细胞中:

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

在TableView中:

 self.tableView.delaysContentTouches = NO; 

对于可以在iOS7和iOS8中工作的解决scheme,创build一个自定义的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; } 

我做了什么来解决这个问题是使用下面的代码的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中按下button时,button反应正确,我的UITableView行为正常,因为不会强制delaysContentTouches

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

 for view in tableView.subviews { if view is UIScrollView { (view as? UIScrollView)!.delaysContentTouches = false break } } 
  - (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; } } } 

在这里输入图像描述

这是RaphaëlPinto上面答案的Swift版本。 不要忘记也upvote他:)

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

Swift中的解决scheme,仅适用于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中的button现在可以立即高亮显示。

我有一个UITableViewCell中的纯文本的UIButton类似的问题没有突出触摸。 什么修复了我的是改变buttonType从自定义回到系统。

将delayContentTouches设置为NO对于同一个UITableViewCell中仅限图像的UIButton执行了这个技巧。

 self.tableView.delaysContentTouches = NO; 

在这里输入图像描述

克里斯·哈里森的答案稍微修改后的版本。 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 } } } } 

我在UITableViewCell上编写了一个类别扩展来简化这个问题。 它与接受的答案基本上是一样的,除了我从UITableViewCell contentView走向视图层次(而不是向下)。

我认为完全“自动化”的解决scheme,将使所有单元格添加到UITableView设置其delaysContentTouches状态匹配拥有UITableViewdelaysContentTouches状态。 为了使这个工作,我不得不swizzle UITableView ,或要求开发人员使用UITableView子类。 不想要求我解决这个我觉得更简单,更灵活的解决scheme。

类别扩展和示例线束:

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 

被接受的答案对我来说并不奏效。

最后,我在uibutton类(/子类)中添加波纹pipe代码,它的工作原理是百分之百。

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

由于objc是dynamic的,scrollView是唯一对DelayContentTouches做出响应的类,所以对于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; } } 

您可能还必须通过selectviewController中的表来closures故事板或笔尖中的“delaysContentTouches”。 顺便说一句,这可能无法在ios 7上工作,如果你在一个viewController中使用tableView,至less我不能得到它的工作。

这个解决scheme对我来说是行不通的,我修改了 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; } 

Swift for iOS 7和8的解决scheme:

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

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

那么我inheritanceUITableView并实现这个:

 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(编码器:)将运行。 请将debugging点放在init函数中,以便知道哪个init函数将运行,然后使用上面的代码使其工作。 希望能帮助别人。

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

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