UIPicker detect tap on currently selected row

后端 未结 8 1379
礼貌的吻别
礼貌的吻别 2020-12-01 10:11

I have a UIPickerView and The method didSelectRow is not called when tapping on a selected row. I need to handle

相关标签:
8条回答
  • 2020-12-01 10:44

    Nikolay's Answer with Swift:

    let tap = UITapGestureRecognizer(target: self, action: #selector(OCAccountSettingsViewController.pickerTapped(_:)))
    tap.cancelsTouchesInView = false
    tap.delegate = self
    pickerView.addGestureRecognizer(tap)
    

    important let your viewController confirm the UIGestureRecognizerDelegate otherwise handler won't fire:

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true}
    

    the last step will be the handler for tap event:

    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
          }
        }
      }
    
    0 讨论(0)
  • 2020-12-01 10:45

    Nikolay's answer in Swift 4:

    First, add a UITapGestureRecognizer to your UIPickerView in viewDidLoad() and let your UIViewController conform to the UIGestureRecognizerDelegate.

    let tap = UITapGestureRecognizer(target: self, action: #selector(pickerTapped))
    tap.delegate = self
    self.pickerView.addGestureRecognizer(tap)
    

    Add this function which calls your UIPickerViewDelegate when a tap on a row has been detected:

    @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)
            }
        }
    }
    

    Add the shouldRecognizeSimultaneouslyWith method from UIGestureRecognizerDelegate:

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    
    0 讨论(0)
  • 2020-12-01 10:46

    Here's swift code for figuring out if user tapped inside the selected row or not. I just converted obj-c code from Nikolay's answer.

    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 ..
        }
    }
    
    0 讨论(0)
  • 2020-12-01 10:47

    Solution touchesBegan: / touchesEnded: worked fine for me when using iOS 4.2/4.3, but they stopped working with iOS. Finally I got this solution which may be helpful: using tap gesture recognition.

        IBOutlet UIPickerView *picker;
    
        [picker addGestureRecognizer:
            [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pickerTapped:)] autorelease]
        ];
    

    In this case when a user taps on picker view, the selector

        -(void)pickerTapped:(UIGestureRecognizer *)gestureRecognizer
    

    is invoked. Worked for me on both iOS 4.2+ / 5.0

    0 讨论(0)
  • 2020-12-01 10:50

    Here's Nikolay's trick in Swift v3:

    First, make your UIViewController implement protocol UIGestureRecognizerDelegate, and add this method to it:

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    

    Then, apply a UITapGestureRecognizer on the picker, and when your target is called, call the following extension method:

    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))
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 10:57

    I solved this by subclassing a common superview and intercepting the touch events before sending them forward. In interface builder, I also added a button where the selector area is, attached an action to the touch up event, and sent the button to "the back" (that's very important so it doesn't return itself in hitTest). The most relevant code is below. It could be improved for more complicated, like multitouch, cases.

        @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;
    }
    
    0 讨论(0)
提交回复
热议问题