iOS-關於一些手勢沖突問題(scrollView 嵌套 tableView)


簡單說下關於開發中容易遇到的父試圖添加手勢與子試圖點擊事件沖突,UIScrollView 嵌套 UIScrollView 、 UIScrollView 嵌套 UITableView的情況手勢沖突問題;

點擊沖突

如果給現有的基於 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;
}

 

scrollView 嵌套 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM