web-dev-qa-db-ja.com

UIPickerは現在選択されている行のタップを検出します

UIPickerViewがあり、メソッドdidSelectRow選択された行をタップしても呼び出されません。このケースを処理する必要があります。何か案は?

39
Royce

まず、クラスを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;
}
25

Swift 4でのニコライの答え:

まず、viewDidLoad()UITapGestureRecognizerUIPickerViewを追加し、UIViewControllerUIGestureRecognizerDelegateに準拠させます。

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
}
14
ElegyD

ニコライの答えSwift

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

重要 viewControllerに確認させますIGestureRecognizerDelegateそうでない場合、ハンドラーは起動しません:

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
      }
    }
  }
10
Dania Delbani

解決 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
Alex Barinov

これがSwiftユーザーが選択した行内をタップしたかどうかを判断するためのコードです。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 ..
    }
}
1
Joosep Simm

一般的なスーパービューをサブクラス化し、タッチイベントをインターセプトしてから転送することで、これを解決しました。 Interface Builderでは、セレクター領域があるボタンを追加し、タッチアップイベントにアクションを添付して、ボタンを「戻る」に送信しました(これは非常に重要なので、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;
}
0
Joe

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))
            }
        }
    }
}
0
jazzgil