iOS UITableView自带滑动手势和父视图添加滑动手势辩说相应机制探索

[复制链接]
发表于 2026-1-27 02:04:21 | 显示全部楼层 |阅读模式
场景

我们偶尔候会遇到如许的一个交互场景:我们有一个UITableView
放在一个弹窗中,这个弹窗可以通过滑动举行展示和消散(跟手滑动的方式),然后这个UITableView放在弹窗中,而且可以滚动,展示一些内容,好比商品信息,品评,(雷同抖音的品评弹窗),而且下滑的时间,如果tableView已经滑动到了顶部,就可以相应滑动手势,继承向下滑动弹窗。
思绪

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

  • (BOOL)gestureRecognizerUIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizerUIGestureRecognizer *)otherGestureRecognizer
    署理方法中,如果gestureRecognizer 是自身的滑动手势,otherGestureRecognizer是tableView 的滑动手势,则必要支持同时相应的,即返回YES,同时,必要有个主意事项,就是如果我们的
    tableView滚动到最顶部了,就必要设置tablView的滚动手势不支持相应,否则的话,就会导致 滚动到顶部的时间,tableView还会继承滚动,如果这个时间往返滑动tableView,就会造成弹窗和tableView 同时滚动的环境,这是我们不想要的,以是我们tablView滚动到顶部的时间,就必要设置tableView的pangesture.enabled = NO.
双滑动手势滚动相应机制

如果我们给tableView的父视图添加一个滑动手势,同时我们在tableView上面滑动,
这时间,如果不支持同时相应,是只有tableView的滑动的,由于默认环境下
上层的优先相应, 而且同时相应默认是关闭的
而且颠末测试发现,如果我们支持同时相应,则上层视图的gestureRecognizerShouldBegin
先实行
,这里就是 tableView 自身滑动手势的gestureRecognizerShouldBegin 先实行,父视图的后实行,这里可以通过自界说一个uitableView的子类来重写gestureRecognizerShouldBegin 方法测试
我们给弹窗添加一个滑动手势,相应方法为handlePan:
通过测试我们发现,我们手在tableView 上滚动的时间,每次实行
tableView 的 署理方法 scrollViewDidScroll 之前,都会实行 handlePan方法。


请看下图
由图可知,手势相应方法是直接出发的,而
scrollViewWillBeginDragging是颠末update之后触发的,以是机会在手势相应方法反面

这里是打印,验证了上面的结论

同样,更新偏移量的方法更是在begindragging 之后了
如图

实行次序

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

这阐明,**在一次滑动手势的相应中, self.tableView.panGestureRecognizer.enabled = NO 的优先级是最高的
以是,使用上面这个特性,我们如果可以在父视图的相应方法中设置tableView的滚动属性
  1. - (void)scrollViewDidScroll:(UIScrollView *)scrollView
  2. {
  3.     NSLog(@"哈哈哈哈哈这里是执行scrollViewDidScroll self.panNum是%ld", self.panNum);
  4. }
复制代码
  1. - (void)handlePan:(UIPanGestureRecognizer *)pan
  2. {
  3.    self.tableView.panGestureRecognizer.enabled = YES;
  4.    NSLog(@"哈哈哈哈哈这是第%ld次响应滑动手势handlePan 方法", self.panNum);
  5.    if (self.panNum % 2 == 0) {
  6.        self.tableView.panGestureRecognizer.enabled = NO;
  7.    } else {
  8.        self.tableView.panGestureRecognizer.enabled = YES;
  9.    }
  10.    self.tableView.panGestureRecognizer.enabled = YES;
  11. }
复制代码

以上测试的完备代码
  1. ////  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
  2. {
  3.     NSLog(@"哈哈哈哈哈这里是执行scrollViewDidScroll self.panNum是%ld", self.panNum);
  4. }
  5. #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
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表