手勢與控制元件事件衝突的解決方案
阿新 • • 發佈:2019-02-10
在日常的開發中我們可能會遇到手勢與UI控制元件事件出現衝突造成監聽事件混亂的情況,其實解決方案非常簡單。在這裡我用點選手勢與UICollectionView的item點選事件作為案例對此方法做一下簡單的介紹。比如有如下案例:
圖中下邊綠色的為UICollectionView,紅色的控制元件為其中的item,現在想要實現點選UICollectionView回收鍵盤,而點選item出現彈窗。我的方法是給UICollectionView新增一個點選的手勢,點選回收鍵盤,然後在UICollectionView的代理方法”- (void)collectionView:(UICollectionView )collectionView didSelectItemAtIndexPath:(NSIndexPath
- (void)viewDidLoad {
[super viewDidLoad];
// 設定介面佈局
[self configureUI];
}
// 介面佈局
- (void)configureUI{
UITextField *textField = [[UITextField alloc]initWithFrame:CGRectMake(10, 30, [UIScreen mainScreen].bounds.size.width-20, 44)];
[self.view addSubview:textField];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.backgroundColor = [UIColor whiteColor];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(([UIScreen mainScreen].bounds.size.width - 80)/ 3, 80);
layout.minimumLineSpacing = 20;
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0 , CGRectGetMaxY(textField.frame)+10, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-CGRectGetMaxY(textField.frame)) collectionViewLayout:layout];
collectionView.delegate = self;
collectionView.dataSource = self;
collectionView.backgroundColor = [UIColor greenColor];
[self.view addSubview:collectionView];
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
// 為collectionView新增手勢,點選回收鍵盤
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(collectionViewClickAction)];
// 利用代理方法解決後邊手勢與item點選事件之間的衝突
tap.delegate = self;
[collectionView addGestureRecognizer:tap];
}
#pragma mark - UICollectionView的資料來源及代理
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 6;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
return cell;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
return UIEdgeInsetsMake(20, 20, 20, 20);
}
// 為了測試增加點選item彈窗的方法
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"測試彈窗" message:@"item被點選了" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
[alertView show];
}
#pragma mark - 手勢相關
// 手勢方法,點選回收鍵盤
- (void)collectionViewClickAction{
[self.view endEditing:YES];
}
但是按照上邊程式碼執行之後會發現”- (void)collectionView:(UICollectionView )collectionView didSelectItemAtIndexPath:(NSIndexPath )indexPath”這個方法在點選item的時候不會執行,而且點選item依然會執行手勢方法回收鍵盤,所以在這裡要利用手勢的代理方法進行判斷,如果點選的檢視是UICollectionView就執行手勢,否則不執行手勢,所以在上邊的程式碼中增加如下方法
// 手勢代理方法
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
// 判斷如果點選的View是UICollectionView就可以執行手勢方法,否則不執行
if ([touch.view isKindOfClass:[UICollectionView class]]) {
return YES;
}
return NO;
}
如此判斷便很好的解決了點選手勢與item點選方法的衝突問題,手勢與其他控制元件的衝突解決方法原理和這個相同,也是利用手勢的代理方法進行判斷,如果手勢執行的檢視不是需要的檢視就不讓其執行。