iOS - Delayed “Touch Down” event for UIButton in UITableViewCell

前端 未结 7 1167
傲寒
傲寒 2020-12-01 00:10

I have a custom UITableViewCell, which is initialized by the following:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIden         


        
相关标签:
7条回答
  • 2020-12-01 00:30

    Swift 3 version of Alex's answer:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        isHighlighted = true
        super.touchesBegan(touches, with: event)
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        isHighlighted = false
        super.touchesEnded(touches, with: event)
    }
    
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        isHighlighted = false
        super.touchesCancelled(touches, with: event)
    }
    
    0 讨论(0)
  • 2020-12-01 00:36

    So why the delay for the "Touch Down" or UIControlStateHighlighted? I'm trying to provide instant feedback to the user to show that the button has been pressed.

    Hasn't Apple explained it yet?

    Without this delay:

    1. If you want to scroll the view, and your finger touches anything highlightable (e.g. any table cell with the default selection style), you get these blinking artifacts:

      Really, they don't know on touchDown, whether you're going to tap or scroll.

    2. If you want to scroll the view, and your finger touches a UIButton/UITextField, the view isn't scrolled at all! Button/TextField's default behavour is "stronger" than the scrollview's, it keeps waiting for a touchUpInside event.

    0 讨论(0)
  • 2020-12-01 00:40

    This is caused by the UIScrollView property delaysContentTouches.

    It used to be sufficient to just set that property to NO for the UITableView itself, but that will only work for subviews of the table that are not encased in another UIScrollView.

    UITableViewCells contain an internal scroll view in iOS 7 so you will need to change the value of this property on the cell level for all cells with buttons in them.

    Here is what you need to do:

    1.in viewDidLoad or somewhere similar once your UITableView has been initialized, put this in:

    self.tableView.delaysContentTouches = NO;
    

    2.for iOS 7 support, in the initialization method for your UITableViewCell (initWithStyle:reuseIdentifier: or initWithCoder: for NIBs), put this in at the end:

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

    This is unfortunately not a 100% permanent solution as Apple can change the view hierarchy inside cells again in the future (perhaps moving the scroll view another layer down or something which would require you to nest another loop in there), but until they surface the class or at least the property to developers somehow, this is the best we've got.

    0 讨论(0)
  • 2020-12-01 00:44

    i solve this problem in my code by subclassing UIButton,

    Objective C

    @interface TBButton : UIButton
    
    @end
    
    @implementation TBButton
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        self.highlighted = true;
        [super touchesBegan:touches withEvent:event];
    }
    
    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        self.highlighted = false;
        [super touchesEnded:touches withEvent:event];
    }
    
    - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        self.highlighted = false;
        [super touchesCancelled:touches withEvent:event];
    }
    
    @end
    

    swift

    class TBButton: UIButton {
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            highlighted = true
            super.touchesBegan(touches, withEvent: event)
        }
    
        override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
            highlighted = false
            super.touchesEnded(touches, withEvent: event)
        }
        override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
            highlighted = false
            super.touchesCancelled(touches, withEvent: event)
        }
    }
    

    swift 3

    class TBButton: UIButton {
        override func touchesBegan(_ touches: Set<UITouch>, with event:     UIEvent?) {
            isHighlighted = true
            super.touchesBegan(touches, with: event)
        }
    
        override func touchesEnded(_ touches: Set<UITouch>, with event:     UIEvent?) {
            isHighlighted = false
            super.touchesEnded(touches, with: event)
        }
    
        override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
            isHighlighted = false
            super.touchesCancelled(touches, with: event)
        }
    }
    
    0 讨论(0)
  • 2020-12-01 00:49

    Maybe this answer is more simple. just add an animation delay to it. like below:

        [self.publishButton bk_addEventHandler:^(id sender) {
        @strongify(self);
        // reset to normal state with delay
        [UIView animateWithDuration:0.1 animations:^{
            self.publishButton.backgroundColor = [UIColor whiteColor];
        }];
        } forControlEvents:UIControlEventTouchUpInside];
    
       [self.publishButton bk_addEventHandler:^(id sender) {
        //Set your Image or color
           self.publishButton.backgroundColor = [UIColor redColor];
       } forControlEvents:UIControlEventTouchDown];
    
    0 讨论(0)
  • 2020-12-01 00:51

    Here's a recursive solution you can add to your view controller:

    + (void)disableDelayedTouches:(UIView*)view
    {
        for(UIView *currentView in view.subviews) {
            if([currentView isKindOfClass:[UIScrollView class]]) {
                ((UIScrollView *)currentView).delaysContentTouches = NO;
            }
            [self disableDelayedTouches:currentView];
        }
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [self.class disableDelayedTouches:self.view];
    }
    
    0 讨论(0)
提交回复
热议问题