iOS UITableView自带滑动手势和父视图添加滑动手势冲突响应机制探索

场景

我们有时候会遇到这样的一个交互场景:我们有一个UITableView
放在一个弹窗中,这个弹窗可以通过滑动进行展示和消失(跟手滑动的方式),然后这个UITableView放在弹窗中,并且可以滚动,展示一些内容,比如商品信息,评论,(类似抖音的评论弹窗),并且下滑的时候,如果tableView已经滑动到了顶部,就可以响应滑动手势,继续向下滑动弹窗。

思路

首先,我们弹窗视图中有一个tableView,这个tableView是可以正常的滑动的,然后,我们在弹窗视图中添加一个滑动手势,手势的响应方法中,修改弹窗的frame。所以,这个弹窗视图是要响应手势的代理
方的,并且 在

  • (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    代理方法中,如果gestureRecognizer 是自身的滑动手势,otherGestureRecognizer是tableView 的滑动手势,则需要支持同时响应的,即返回YES,同时,需要有个主意事项,就是如果我们的
    tableView滚动到最顶部了,就需要设置tablView的滚动手势不支持响应,否则的话,就会导致 滚动到顶部的时候,tableView还会继续滚动,如果这个时候来回滑动tableView,就会造成弹窗和tableView 同时滚动的情况,这是我们不想要的,所以我们tablView滚动到顶部的时候,就需要设置tableView的pangesture.enabled = NO.

双滑动手势滚动响应机制

我们给弹窗添加一个滑动手势,响应方法为handlePan:
通过测试我们发现,我们手在tableView 上滚动的时候,每次执行
tableView 的 代理方法 scrollViewDidScroll 之前,都会执行 handlePan方法。

请添加图片描述

并且,在一次滑动(手没有脱离屏幕算同一次滑动)过程中,
如果响应方法 handlePan 中有设置过
self.tableView.panGestureRecognizer.enabled = NO; 就会导致
本次滑动中self.tableView 不会滚动,即便在self.tableView.panGestureRecognizer.enabled = NO后面设置了 self.tableView.panGestureRecognizer.enabled = YES也不会滚动

这说明,**在一次滑动手势的响应中, self.tableView.panGestureRecognizer.enabled = NO 的优先级是最高的

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

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

请添加图片描述

以上测试的完整代码

//
//  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. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 21:56:05       5 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 21:56:05       5 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 21:56:05       4 阅读
  4. Python语言-面向对象

    2024-07-10 21:56:05       7 阅读

热门阅读

  1. 【对抗算法复现】CW

    2024-07-10 21:56:05       6 阅读
  2. vscode无法切换env环境

    2024-07-10 21:56:05       8 阅读
  3. GCN-LSTM实现时空预测

    2024-07-10 21:56:05       7 阅读
  4. 泛型

    泛型

    2024-07-10 21:56:05      7 阅读
  5. 二分查找(红绿标记法)

    2024-07-10 21:56:05       8 阅读