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
相关推荐
️ 邪神3 分钟前
【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
flutter·ios·鸿蒙·reactnative·anroid
soulteary36 分钟前
突破内存限制:Mac Mini M2 服务器化实践指南
运维·服务器·redis·macos·arm·pika
小江村儿的文杰11 小时前
XCode Build时遇到 .entitlements could not be opened 的问题
ide·macos·ue4·xcode
比格丽巴格丽抱12 小时前
flutter项目苹果编译运行打包上线
flutter·ios
网络安全-老纪13 小时前
iOS应用网络安全之HTTPS
web安全·ios·https
天涯倦客的美丽人生13 小时前
2024年11月最新 Alfred 5 Powerpack (MACOS)下载
macos
SoraLuna13 小时前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie
总爱写点小BUG14 小时前
VM虚拟机装MAC后无法联网,如何解决?
macos
1024小神15 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
lzhdim17 小时前
iPhone 17 Air看点汇总:薄至6mm 刷新苹果轻薄纪录
ios·iphone