我有一个并且在点击选定行时不会调用UIPickerView
该方法。我需要处理这个案子。有任何想法吗?didSelectRow
8 回答
首先,使类符合UIGestureRecognizerDelegate
协议
然后,在视图设置中:
UITapGestureRecognizer *tapToSelect = [[UITapGestureRecognizer alloc]initWithTarget:self
action:@selector(tappedToSelectRow:)];
tapToSelect.delegate = self;
[self.pickerView addGestureRecognizer:tapToSelect];
在其他地方:
#pragma mark - Actions
- (IBAction)tappedToSelectRow:(UITapGestureRecognizer *)tapRecognizer
{
if (tapRecognizer.state == UIGestureRecognizerStateEnded) {
CGFloat rowHeight = [self.pickerView rowSizeForComponent:0].height;
CGRect selectedRowFrame = CGRectInset(self.pickerView.bounds, 0.0, (CGRectGetHeight(self.pickerView.frame) - rowHeight) / 2.0 );
BOOL userTappedOnSelectedRow = (CGRectContainsPoint(selectedRowFrame, [tapRecognizer locationInView:self.pickerView]));
if (userTappedOnSelectedRow) {
NSInteger selectedRow = [self.pickerView selectedRowInComponent:0];
[self pickerView:self.pickerView didSelectRow:selectedRow inComponent:0];
}
}
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return true;
}
Nikolay 在Swift 4中的回答:
首先,将 a 添加UITapGestureRecognizer
到您的UIPickerView
inviewDidLoad()
并让您UIViewController
符合UIGestureRecognizerDelegate
.
let tap = UITapGestureRecognizer(target: self, action: #selector(pickerTapped))
tap.delegate = self
self.pickerView.addGestureRecognizer(tap)
添加此函数,当检测到对一行的点击时调用您的 UIPickerViewDelegate:
@objc func pickerTapped(tapRecognizer: UITapGestureRecognizer) {
if tapRecognizer.state == .ended {
let rowHeight = self.pickerView.rowSize(forComponent: 0).height
let selectedRowFrame = self.pickerView.bounds.insetBy(dx: 0, dy: (self.pickerView.frame.height - rowHeight) / 2)
let userTappedOnSelectedRow = selectedRowFrame.contains(tapRecognizer.location(in: self.pickerView))
if userTappedOnSelectedRow {
let selectedRow = self.pickerView.selectedRow(inComponent: 0)
pickerView(self.pickerView, didSelectRow: selectedRow, inComponent: 0)
}
}
}
从添加shouldRecognizeSimultaneouslyWith
方法UIGestureRecognizerDelegate
:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
Nikolay 对Swift的回答:
let tap = UITapGestureRecognizer(target: self, action: #selector(OCAccountSettingsViewController.pickerTapped(_:)))
tap.cancelsTouchesInView = false
tap.delegate = self
pickerView.addGestureRecognizer(tap)
重要的是让您的 viewController 确认UIGestureRecognizerDelegate否则处理程序不会触发:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true}
最后一步将是点击事件的处理程序:
func pickerTapped(tapRecognizer:UITapGestureRecognizer)
{
if (tapRecognizer.state == UIGestureRecognizerState.Ended)
{
let rowHeight : CGFloat = self.pickerView.rowSizeForComponent(0).height
let selectedRowFrame: CGRect = CGRectInset(self.pickerView.bounds, 0.0, (CGRectGetHeight(self.pickerView.frame) - rowHeight) / 2.0 )
let userTappedOnSelectedRow = (CGRectContainsPoint(selectedRowFrame, tapRecognizer.locationInView(pickerView)))
if (userTappedOnSelectedRow)
{
let selectedRow = self.pickerView.selectedRowInComponent(0)
//do whatever you want here
}
}
}
解决方案touchesBegan:
/touchesEnded:
在使用 iOS 4.2/4.3 时对我来说效果很好,但他们停止使用 iOS。最后我得到了这个可能有用的解决方案:使用轻击手势识别。
IBOutlet UIPickerView *picker;
[picker addGestureRecognizer:
[[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pickerTapped:)] autorelease]
];
在这种情况下,当用户点击选择器视图时,选择器
-(void)pickerTapped:(UIGestureRecognizer *)gestureRecognizer
被调用。在 iOS 4.2+ / 5.0 上为我工作
这是用于确定用户是否在所选行内点击的快速代码。我刚刚从 Nikolay 的答案中转换了 obj-c 代码。
func pickerTapped(sender: UITapGestureRecognizer){
let rowHeight = self.rowSizeForComponent(0).height
let selectedRowFrame = CGRectInset(self.bounds, 0.0, (CGRectGetHeight(self.frame) - rowHeight) / 2.0)
let userTappedOnSelectedRow = CGRectContainsPoint(selectedRowFrame, sender.locationInView(self))
if( userTappedOnSelectedRow ){
// .. your action here ..
}
}
我通过继承一个通用的超级视图并在发送它们之前拦截触摸事件来解决这个问题。在界面生成器中,我还在选择器区域所在的位置添加了一个按钮,将一个动作附加到了触摸事件,并将按钮发送到“后部”(这非常重要,因此它不会在 hitTest 中返回自身)。最相关的代码如下。对于更复杂的情况,例如多点触控,它可以得到改进。
@implementation InterceptorView
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *t=[touches anyObject];
CGPoint p=[t locationInView:button];
if ([button hitTest:p withEvent:event])
started_in_button=YES;
[hitView touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[hitView touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *t=[touches anyObject];
CGPoint p=[t locationInView:button];
if ([button hitTest:p withEvent:event] && started_in_button) {
started_in_button=NO;
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
[hitView touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[hitView touchesCancelled:touches withEvent:event];
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
hitView = [super hitTest:point withEvent:event];
return self;
}
这是 Nikolay 在 Swift v3 中的技巧:
首先,让你的 UIViewController 实现协议 UIGestureRecognizerDelegate,并添加这个方法:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
然后,在选取器上应用一个 UITapGestureRecognizer,当你的目标被调用时,调用以下扩展方法:
extension UIPickerView {
func pickerTapped(nizer: UITapGestureRecognizer, onPick: @escaping (Int) -> ()) {
if nizer.state == .ended {
let rowHeight = self.rowSize(forComponent: 0).height
let selectedRowFrame = self.bounds.insetBy(dx: 0, dy: (self.frame.height - rowHeight) / 2)
// check if begin and end tap locations both fall into the row frame:
if selectedRowFrame.contains(nizer.location(in: self)) &&
selectedRowFrame.contains(nizer.location(ofTouch: 0, in: self)) {
onPick(self.selectedRow(inComponent: 0))
}
}
}
}
按照已经建议,将 tapGestureRecognizer 添加到 pickerView
提供选择器行的视图,而不是标题,通过
-(UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
在手势的回调方法中执行此操作
-(void)pickerTapped:(UIGestureRecognizer *)gestureRecognizer {
UIPickerView * pv = (id)gestureRecognizer.view;
UIView * selView = [pv viewForRow:[pv selectedRowInComponent:0]
forComponent:0];
CGPoint touchPoint = [gestureRecognizer locationInView:selView];
BOOL tapOnSelection = CGRectContainsPoint(selView.bounds, touchPoint);
if (tapOnSelection) ...
}
我认为比做像素数学更优雅