iOS-关于一些手势冲突问题(scrollView 嵌套 tableView)

简单说下关于开发中容易遇到的父试图添加手势与子试图点击事件冲突,UIScrollView 嵌套 UIScrollView 、 UIScrollView 嵌套 UITableView的情况手势冲突问题;

1|0点击冲突

如果给现有的基于 UIView 的 xkTestView 上加一个点击手势 gestTap,然后在 xkTestView 中间区域添加一个 tableview,我们想响应 gestTap,同时也想响应 tableview 的 cell 点击代理事件,这时可以添加 gestTap 点击手势代理:

<UIGestureRecognizerDelegate>

然后在点击事件代理方法中实现

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([NSStringFromClass([touch.view class]) isEqualToString:@"xkTestView"]) { return YES; } return NO; }

2|0 

3|0scrollView 嵌套 tableView 类冲突

这里直接用 scrollView 嵌套 tableView 来处理下滑动时的手势冲突问题,其实苹果并不建议我们这样做,但是在实际项目中,有些需求会经常用嵌套来实现,在什么情况下滑动 tableView 不滑动 scrollView,什么情况下滑动 scrollView 不滑动 tableView,其实如果做其他的嵌套都是一样的,先看下最终效果图:

 

1)首先新建一个基于 UIScrollView 的 XKBaseScrollView ,并实现 <UIGestureRecognizerDelegate> 代理,XKBaseScrollView 用做主父试图来添加子试图内容

 XKBaseScrollView.h

#import <UIKit/UIKit.h> @interface XKBaseScrollView : UIScrollView <UIGestureRecognizerDelegate> @end

 

XKBaseScrollView.m

#import "XKBaseScrollView.h" @implementation XKBaseScrollView //是否支持多时候触发,这里返回YES -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } @end

 

2)然后新建一个基于 UITableView 的 XKTargetTableView ,并实现 <UIGestureRecognizerDelegate,UITableViewDelegate,UITableViewDataSource> 代理

XKTargetTableView.h

#import <UIKit/UIKit.h> @interface XKTargetTableView : UITableView ///可否滑动 @property (nonatomic,assign) BOOL canSlide; ///滑动block通知 @property (nonatomic,copy) void (^slideDragBlock)(void); @end

 

XKTargetTableView.m

#import "XKTargetTableView.h" @interface XKTargetTableView ()<UIGestureRecognizerDelegate,UITableViewDelegate,UITableViewDataSource> @property (nonatomic,assign) CGFloat currOffsetY; @end @implementation XKTargetTableView - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style{ self = [super initWithFrame:frame style:style]; if (self) { self.backgroundColor = [UIColor whiteColor]; self.delegate = self; self.dataSource = self; self.tableFooterView = [UIView new]; [self registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; } return self; } //是否支持多时候触发,这里返回YES - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } #pragma mark ========== tableView 代理 ========== - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 20; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 50; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"]; cell.textLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row]; return cell; } #pragma mark ========== scrollview 代理 ========== - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ _currOffsetY = scrollView.contentOffset.y; } -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ if (!self.canSlide) { scrollView.contentOffset = CGPointMake(0, scrollView.contentOffset.y == 0 ? 0 : _currOffsetY); } _currOffsetY = scrollView.contentOffset.y; if (scrollView.contentOffset.y < 0 ) { self.canSlide = NO; scrollView.contentOffset = CGPointZero; //到顶通知父视图改变状态 if (self.slideDragBlock) { self.slideDragBlock(); } } scrollView.showsVerticalScrollIndicator = self.canSlide ? YES : NO; } @end

 

3)最后在使用的 ViewController 中实现

#import "ViewController.h" #import <SDAutoLayout.h> #import "XKBaseScrollView.h" #import "XKTargetTableView.h" @interface ViewController ()<UIScrollViewDelegate> ///容器 @property (nonatomic,strong) XKBaseScrollView *scrollView; @property (nonatomic,strong) XKTargetTableView *tableView; ///是否可以滑动 scrollView @property (nonatomic,assign) BOOL canSlide; @property (nonatomic,assign) CGFloat lastPositionY; ///滑动临界范围值 @property (nonatomic,assign) CGFloat dragCriticalY; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. _dragCriticalY = 200; [self.view addSubview:self.scrollView]; self.scrollView.sd_layout. topSpaceToView(self.view, 0). leftSpaceToView(self.view, 0). rightSpaceToView(self.view, 0). bottomSpaceToView(self.view, 0); [self.scrollView setupAutoContentSizeWithBottomView:self.tableView bottomMargin:0]; __weak __typeof__(self) weekSelf = self; self.tableView.slideDragBlock = ^{ weekSelf.canSlide = YES; weekSelf.tableView.canSlide = NO; }; } -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ CGFloat currentPostion = scrollView.contentOffset.y; /* 当 底层滚动式图滚动到指定位置时, 停止滚动,开始滚动子视图 */ if (currentPostion >= self.dragCriticalY) { scrollView.contentOffset = CGPointMake(0, self.dragCriticalY); if (self.canSlide) { self.canSlide = NO; self.tableView.canSlide = YES; } else{ if (_lastPositionY - currentPostion > 0){ if (self.tableView.contentOffset.y > 0) { self.tableView.canSlide = YES; self.canSlide = NO; } else{ self.tableView.canSlide = NO; self.canSlide = YES; } } } }else{ if (!self.canSlide && scrollView.contentOffset.y == self.dragCriticalY ) { scrollView.contentOffset = CGPointMake(0, self.dragCriticalY); } else{ if (self.tableView.canSlide && self.tableView.contentOffset.y != 0) { scrollView.contentOffset = CGPointMake(0, self.dragCriticalY); } else{ } } } _lastPositionY = currentPostion; } - (XKBaseScrollView *)scrollView{ if (!_scrollView) { _scrollView = [[XKBaseScrollView alloc]init]; _scrollView.showsVerticalScrollIndicator = NO; _scrollView.delegate = self; _scrollView.backgroundColor = [UIColor redColor]; UIView *view = [[UIView alloc]init]; view.backgroundColor = [UIColor blueColor]; [_scrollView addSubview:view]; view.sd_layout. topSpaceToView(_scrollView, 0). leftSpaceToView(_scrollView, 0). rightSpaceToView(_scrollView, 0). heightIs(300); [_scrollView addSubview:self.tableView]; self.tableView.sd_layout. topSpaceToView(view, 0). leftSpaceToView(_scrollView, 0). rightSpaceToView(_scrollView, 0). heightIs(self.view.bounds.size.height - (300 - self.dragCriticalY)); } return _scrollView; } - (XKTargetTableView *)tableView{ if(!_tableView){ _tableView = [[XKTargetTableView alloc]initWithFrame:CGRectZero style:UITableViewStylePlain]; } return _tableView; } @end

 

注:此 demo 需引用 SDAutoLayout


__EOF__

本文作者K
本文链接https://www.cnblogs.com/wangkejia/p/11081577.html
关于博主:评论和私信尽量在第一时间回复哦~
版权声明:如果您要转载,请注明出处哦~
声援博主:如果觉得文章对您有帮助,点击文章右下角【推荐】一下吧~
posted @   macroK  阅读(9940)  评论(3编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示