У меня есть UIPickerView
и метод didSelectRow
не вызывается при нажатии на выбранную строку. Мне нужно справиться с этим делом. Есть идеи?
UIPicker обнаруживает ответ на выбранную строку
Ответ 1
Сначала совместим класс с протоколом 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;
}
Ответ 2
Николай Отвечать с помощью 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}
последним шагом будет обработчик события tap:
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
}
}
}
Ответ 3
Николай отвечает в Swift 4:
Во-первых, добавьте UITapGestureRecognizer
в ваш UIPickerView
в viewDidLoad()
и пусть ваш 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
}
Ответ 4
Решение 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
Ответ 5
Здесь быстрый код для выяснения, если пользователь задействован внутри выбранной строки или нет. Я просто конвертировал 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 ..
}
}
Ответ 6
Я решил это, подклассифицировав общий просмотр и перехватив события касания, прежде чем отправлять их вперед. В построителе интерфейса я также добавил кнопку, в которой находится область выбора, приложила действие к событию касания и отправила кнопку "назад" (это очень важно, чтобы она не возвращалась в 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;
}
Ответ 7
Здесь трюк Николая в 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))
}
}
}
}