Technology Sharing

Exploration on the conflict response mechanism between iOS UITableView's built-in sliding gesture and the parent view adding sliding gesture

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Scenes

Sometimes we encounter such an interaction scenario: we have a UITableView
It is placed in a pop-up window, which can be displayed and disappeared by sliding (following the sliding of the hand), and then the UITableView is placed in the pop-up window and can scroll to display some content, such as product information and comments (similar to the comment pop-up window of Tik Tok), and when sliding down, if the tableView has slid to the top, it can respond to the sliding gesture and continue to slide the pop-up window down.

Ideas

First, we have a tableView in the pop-up view, and this tableView can slide normally. Then, we add a sliding gesture to the pop-up view, and modify the pop-up frame in the gesture response method. Therefore, this pop-up view is the proxy that responds to the gesture.
square, and in

  • (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    In the proxy method, if gestureRecognizer is its own sliding gesture and otherGestureRecognizer is the sliding gesture of tableView, it is necessary to support simultaneous response, that is, return YES. At the same time, there is an idea that if our
    When the tableView scrolls to the top, you need to set the scroll gesture of the tablView to not support response. Otherwise, when it scrolls to the top, the tableView will continue to scroll. If you slide the tableView back and forth at this time, the pop-up window and the tableView will scroll at the same time, which is what we don’t want. So when the tablView scrolls to the top, we need to set the tableView’s pangesture.enabled = NO.

Double swipe gesture scroll response mechanism

We add a sliding gesture to the pop-up window, and the response method is handlePan:
Through testing, we found thatWhen we scroll on the tableView, each time we execute
The handlePan method is executed before the tableView's proxy method scrollViewDidScroll.

Please add a description of the image

And, during a slide (the hand does not leave the screen and counts as one slide),
If the response method handlePan has been set
self.tableView.panGestureRecognizer.enabled = NO; will result in
During this slide, self.tableView will not scroll, even if self.tableView.panGestureRecognizer.enabled = NO is followed by self.tableView.panGestureRecognizer.enabled = YES.

This shows that, in the response to a sliding gesture, self.tableView.panGestureRecognizer.enabled = NO has the highest priority.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSLog(@"哈哈哈哈哈这里是执行scrollViewDidScroll self.panNum是%ld", self.panNum);
}

  • 1
  • 2
  • 3
  • 4
  • 5
- (void)handlePan:(UIPanGestureRecognizer *)pan
{
   self.tableView.panGestureRecognizer.enabled = YES;

   NSLog(@"哈哈哈哈哈这是第%ld次响应滑动手势handlePan 方法", self.panNum);
   if (self.panNum % 2 == 0) {
       self.tableView.panGestureRecognizer.enabled = NO;
   } else {
       self.tableView.panGestureRecognizer.enabled = YES;
   }
   self.tableView.panGestureRecognizer.enabled = YES;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Please add a description of the image

The complete code for the above test

//
//  LBPangestureController.m
//  TEXT
//
//  Created by mac on 2024/7/7.
//  Copyright © 2024 刘博. All rights reserved.
//

#import "LBPangestureController.h"

@interface LBPangestureController () <UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate>

@property (nonatomic, strong) UITableView *tableView;

@property (nonatomic, strong) UIPanGestureRecognizer *pangesture;

@property (nonatomic, assign) NSInteger panNum;

@end

@implementation LBPangestureController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.tableView];
    [self.view addGestureRecognizer:self.pangesture];
    // Do any additional setup after loading the view.
}


- (void)handlePan:(UIPanGestureRecognizer *)pan
{
    self.tableView.panGestureRecognizer.enabled = YES;

    NSLog(@"哈哈哈哈哈这是第%ld次响应滑动手势handlePan 方法", self.panNum);
    if (self.panNum % 2 == 0) {
        self.tableView.panGestureRecognizer.enabled = NO;
    } else {
        self.tableView.panGestureRecognizer.enabled = YES;
    }
    self.tableView.panGestureRecognizer.enabled = YES;
}

#pragma mark  - UITableViewDelegate, UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([UITableViewCell class])];
    cell.textLabel.text = [NSString stringWithFormat:@"%ld", indexPath.row];
    return cell;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 100;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 60;
}

#pragma mark - uiscrollViewdelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSLog(@"哈哈哈哈哈这里是执行scrollViewDidScroll self.panNum是%ld", self.panNum);
}

#pragma mark - gesturedelegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.pangesture) {
        self.panNum ++;
    }
    return YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if (gestureRecognizer == self.pangesture && otherGestureRecognizer == self.tableView.panGestureRecognizer) {
        return YES;
    }
    return NO;
}

#pragma mark - lazy load

- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 100, 300, 400) style:UITableViewStylePlain];
        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:NSStringFromClass([UITableViewCell class])];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.backgroundColor = [UIColor cyanColor];
    }
    return _tableView;
}

- (UIPanGestureRecognizer *)pangesture
{
    if (!_pangesture) {
        _pangesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
        _pangesture.delegate = self;
    }
    return _pangesture;
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122