UIPickerView
があり、メソッドdidSelectRow
は選択された行をタップしても呼び出されません。このケースを処理する必要があります。何か案は?
まず、クラスを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;
}
Swift 4でのニコライの答え:
まず、viewDidLoad()
のUITapGestureRecognizer
にUIPickerView
を追加し、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
}
ニコライの答え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
}
}
}
解決 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の両方で私のために働いた
これが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 ..
}
}
一般的なスーパービューをサブクラス化し、タッチイベントをインターセプトしてから転送することで、これを解決しました。 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;
}
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))
}
}
}
}