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
子类。
使用这个示例UITableView
的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
的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; }
我做了什么来解决这个问题是使用下面的代码的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
状态匹配拥有UITableView
的delaysContentTouches
状态。 为了使这个工作,我不得不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类(/子类)中添加下面的代码,它的工作原理是百分之百。
- (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() } } }