IOS7/8 UIButton highlighted state latency problem solution, ios7uibutton
It is estimated that many coders have encountered such a situation:
In some cases, UIButton cannot immediately respond to the TouchDown event. In other words, when you click a button quickly, you will never see the highlighted state of the button.
In this case, all the buttons are in UIScrollView.
For this reason, I spent one afternoon checking and sorting out the perfect solution.
Before introducing the solution, we must popularize some facts to help you understand:
UIScrollView:
1. Attribute delaysContentTouches, Boolean Type, default value: YES. When the value is YES, UIScrollView will delay Ms when receiving the gesture to determine whether the gesture can start the sliding event of UIScrollView; when the value is NO, UIScrollView immediately distributes received gestures to the subview.
(Note: This setting is not enough. You will find that if you want to drag the scrollView and the start point will not be moved when it falls on another view with Gesture Recognition)
2. Method-(BOOL) touchesShouldCancelInContentView :( UIView *) view. The overload of this method is the key to help us solve the problem perfectly. It determines whether the gesture is canceled and passed to the view, triggered when a ScrollView is dragged. When NO is returned, the drag gesture remains on the ScrollView. If YES is returned, the gesture is uploaded to the view. (If the view is UIControl, YES is returned by default)
UITableView:
I have to say that the view structure of UITableView (including UITableViewCell) in iOS7 and iOS8 is different, and there are many views that we will never be able to access during coding, however, we can use Debug to find its subviews one by one. This is related to the depth of our problem.
IOS7: There are n + 1 UIScrollView in UITableView, one is UITableView itself, and the other n exist between the contentView of UITableViewCell and cell. The class name is UITableViewCellScrollView, which is active soon, it only exists in iOS7 and has been removed from ios8.
IOS8: There are two uiscrollviews in UITableView. One is UITableView itself, and the other exists between UITableView and UITableViewCell. The class name is UITableViewWrapperView. Note that UITableViewWrapperView is not a UIScrollView in iOS7.
After the knowledge of science popularization, we have the following solutions:
1. Set the delaysContentTouches attribute of all UIButton parent views belonging to UIScrollView to NO.
2. inherit UIScrollView or UITableView, and overwrite the-(BOOL) touchesShouldCancelInContentView :( UIView *) view method to let it respond to the drag method.
The following is the reference code:
For ease, I wrote subclass of two classes in the same file.
NoDelayButtonScrollView. h:
#import <UIKit/UIKit.h>@interface NoDelayButtonScrollView : UIScrollView@end@interface NoDelayButtonTableView : UITableView@end
NoDelayButtonScrollView. m (1 ):
#import "NoDelayButtonScrollView.h"@implementation NoDelayButtonScrollView- (id)initWithCoder:(NSCoder *)aDecoder{ self = [super initWithCoder:aDecoder]; if (self) { self.delaysContentTouches = NO; } return self;}- (BOOL)touchesShouldCancelInContentView:(UIView *)view{ if ([view isKindOfClass:[UIButton class]]) { return YES; } return [super touchesShouldCancelInContentView:view];}@end
NoDelayButtonScrollView. m (2 ):
@implementation NoDelayButtonTableView- (id)initWithCoder:(NSCoder *)aDecoder{ self = [super initWithCoder:aDecoder]; if (self) {self.delaysContentTouches = NO; // 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;}- (BOOL)touchesShouldCancelInContentView:(UIView *)view{ if ([view isKindOfClass:[UIButton class]]) { return YES; } return [super touchesShouldCancelInContentView:view];}@end
The preceding sections inherit UIScrollView and UITableView, respectively, and rewrite initWithCoder: The method ensures that the Nib file can also take effect.
The ScrollView and TableView written by these two classes can quickly respond to the TouchDown event of the sub-Button and display the highlighted
However, the above Code still fails to solve the problem of UITableView sub-Button highlighted delay in iOS7.
You can add the following code to solve the problem:
for (id obj in cell.subviews){ if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"]) { UIScrollView *scroll = (UIScrollView *) obj; scroll.delaysContentTouches = NO; break; }}
This code can be added to the initWithCoder: Method of UITableViewCell of Custom, or in the cellForRowAtIndexPath of UITableViewDelegate: method to set the UITableViewCellScrollView in the corresponding cell.
The above are all methods to help you solve the problem of Button latency highlighting.