我正在添加一个uipickerview作为主视图的子视图。要在点击背景视图时关闭选择器视图,我将在主视图中添加UITapGestureRecognizer。
我使用以下代码为主视图添加GestureRecognizer
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
gestureRecognizer.numberOfTapsRequired=1;
gestureRecognizer.numberOfTouchesRequired=1;
gestureRecognizer.delegate = self;
[self.view addGestureRecognizer:gestureRecognizer];
[gestureRecognizer release];
在handleSingleTap方法中,我正在解雇pickerview。
但问题是当我在pickerview内部点击时也会调用handleSingleTap。为避免这种情况,我使用了以下UIGestureRecognizer的委托方法
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
/*
*If the tap is inside a button return NO, to ensure the button click is detected.
*/
if ([touch.view isKindOfClass:[UIButton class]]){
return FALSE;
}else if([touch.view isKindOfClass:[UIPickerView class]]) {
return FALSE;
}
return TRUE;
}
它适用于按钮,但不适用于UIPickerView
。任何人都可以帮我这个吗?
答案 0 :(得分:1)
触摸的视图(touch.view)可能是pickerview的子视图之一。我试着测试一下:
[[pickerview subviews] containsObject: touch.view];
答案 1 :(得分:1)
我已根据您的特定要求编制了解决方案。
首先,我按照您的描述实现了您的代码并观察了您报告的相同问题 - 当您点击任何内容时,虚假的点按事件被发送到点击处理程序,包括UIButton。
这告诉我,UITapGestureRecogniser“窃取”应该转到UIButton的触摸,因此我认为最简单,最实用的解决方案是使用该功能对我有利,因此我为这两个分配了一个UITapGestureRecogniser pickerview和按钮也。我们刚刚丢弃的pickerview的水龙头,我们解析的其他水龙头并传递给按钮的水龙头处理程序。
注意 - 为方便起见,我在xib中分配了pickerview的数据源和委托。你也需要这样做,或者在代码中设置它。
标题强>
//
// ViewController.h
// stackExchangeDemo
//
// Created by unsynchronized on 18/01/12.
// released to public domain via http://stackoverflow.com/a/8908028/830899
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
<UIPickerViewDelegate, UIPickerViewDataSource>
{
UIButton *btn1;
UIPickerView *picker1;
}
@property (retain, nonatomic) IBOutlet UIButton *btn1;
@property (retain, nonatomic) IBOutlet UIPickerView *picker1;
@end
<强>实施强>
//
// ViewController.m
// stackExchangeDemo
//
// Created by unsynchronized on 18/01/12.
// released to public domain via http://stackoverflow.com/a/8908028/830899
//
#import "ViewController.h"
@implementation ViewController
@synthesize btn1;
@synthesize picker1;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
-(void) handleSingleTap:(UITapGestureRecognizer *) tapper {
if (tapper.state == UIGestureRecognizerStateEnded) {
NSLog(@"%@",NSStringFromSelector(_cmd));
}
}
- (IBAction)handleButtonTap:(id)sender {
NSLog(@"%@",NSStringFromSelector(_cmd));
}
-(void) handleButtonTapGesture:(UITapGestureRecognizer *) tapper {
// call the buttons event handler
UIControlEvents eventsToHandle = UIControlEventTouchUpInside;
if (tapper.state == UIGestureRecognizerStateEnded) {
UIButton *btn = (UIButton *) tapper.view;
for (NSString *selName in [btn actionsForTarget:self forControlEvent:eventsToHandle]) {
SEL action = NSSelectorFromString(selName);
if (action) {
[self performSelector:action withObject:btn1];
break;
}
};
}
}
-(void) handleDummyTap:(UITapGestureRecognizer *) tapper {
// silently ignore the tap event for this view.
}
-(void) setupTap:(UIView *) view action:(SEL)action {
// assign custom tap event handler for given view.
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:action];
[view addGestureRecognizer:gestureRecognizer];
[gestureRecognizer release];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setupTap:self.view action:@selector(handleSingleTap:)];
[self setupTap:picker1 action:@selector(handleDummyTap:)];
[self setupTap:btn1 action:@selector(handleButtonTapGesture:)];
}
- (void)viewDidUnload
{
[self setBtn1:nil];
[self setPicker1:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark @protocol UIPickerViewDataSource<NSObject>
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return 1;
}
#pragma mark @protocol UIPickerViewDelegate<NSObject>
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [@"so long and thanks for all the fish".copy autorelease ];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
NSLog(@"%@",NSStringFromSelector(_cmd));
}
- (void)dealloc {
[btn1 release];
[picker1 release];
[super dealloc];
}
@end
答案 2 :(得分:0)
我只是在UIPickerView后面添加了一个不可见的UIControl实例,它覆盖了所有窗口,并获得了UIPickerView背后的所有触摸。如果被触摸,则UIPickerView和UIControl都被解除。 (SelectButton和CancelButton是UIPickerView的附件按钮。)
@property (strong, nonatomic) UIControl *touchRecognizer;
- (IBAction)showPicker:(id)sender {
self.touchRecognizer = [[UIControl alloc]initWithFrame:self.view.window.bounds];
[self.view.window addSubview:self.touchRecognizer];
[self.touchRecognizer addTarget:self action:@selector(touchedOutsidePicker:) forControlEvents:UIControlEventTouchUpInside];
[self.textField becomeFirstResponder];
}
- (IBAction)touchedOutsidePicker:(id)sender {
[self.touchRecognizer removeFromSuperview];
self.touchRecognizer = nil;
[self.textField resignFirstResponder];
}
-(void)selectButtonPressed:(id)sender{
[self.touchRecognizer removeFromSuperview];
self.touchRecognizer = nil;
[self.textField resignFirstResponder];
}
-(void)cancelButtonPressed:(id)sender{
[self.touchRecognizer removeFromSuperview];
self.touchRecognizer = nil;
[self.textField resignFirstResponder];
}
答案 3 :(得分:0)
我在Swift中实现了以下内容:
override func viewDidLoad()
{
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
func handleTapGesture(sender: AnyObject)
{
let subview = view?.hitTest(sender.locationInView(view), withEvent: nil)
if(!(subview?.isDescendantOfView(timePicker) ?? false))
{//might want to add a condition to make sure it's not your button ^^
showTimePicker(false)//method which handles showing/hiding my picker
}
}