UIView
には4つのボタンがあり、ボタンビューの上部には別のUIView
があります。一番上のビューには、UIImageView
が付いたUITapGestureRecognizer
が含まれています。
私が作成しようとしている動作は、ユーザーがUIImageView
をタップすると、画面の右下隅にある小さいサイズと、大きくなるようにアニメートするモードを切り替えることです。大きい場合は底面図のボタンを無効にし、小さい場合は右下隅にあるボタンにタッチを通過させ、ボタンが通常どおり動作するようにします。私はほとんどそこにいますが、トップビューのUserInteractions
を無効にしない限り、タッチをボタンに渡すことができません。
トップビューのinitWithFrame:
にこれがあります:
// Add a gesture recognizer to the image view
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapped:)];
tapGestureRecognizer.cancelsTouchesInView = NO;
[imageView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];
そして私はこれが私のimageTapped:
メソッドです:
- (void) imageTapped:(UITapGestureRecognizer *) gestureRecognizer {
// Toggle between expanding and contracting the image
if (expanded) {
[self contractAnimated:YES];
expanded = NO;
gestureRecognizer.cancelsTouchesInView = NO;
self.userInteractionEnabled = NO;
self.exclusiveTouch = NO;
}
else {
[self expandAnimated:YES];
expanded = YES;
gestureRecognizer.cancelsTouchesInView = NO;
self.userInteractionEnabled = YES;
self.exclusiveTouch = YES;
}
}
上記のコードでは、画像が大きい場合、ボタンは非アクティブになり、画像に触れると縮小し、ボタンがアクティブになります。ただし、小さな画像はタッチを受けないため、拡大しません。
両方の場合にself.userInteractionEnabled = YES
を設定すると、タッチすると画像が伸縮しますが、ボタンはタッチを受け取らず、無効のように動作します。
タッチされたときに画像を拡大および縮小するために、画像が縮小状態にある場合にのみ下のボタンがタッチを受け取るために離れていますか?私はここで何か愚かなことをしていて、明らかなことを見逃していますか?
私はこれが機能するようにしようとして絶対に怒っていますので、どんな助けも感謝します、
デイブ
更新:
さらにテストするために、touchesBegan:
メソッドとtouchesCancelled:
メソッドをオーバーライドし、UIImageViewを含むビューでそれらのスーパー実装を呼び出しました。上記のコードでは、touchesCancelled:
は呼び出されず、touchesBegan:
は常に呼び出されます。
そのため、ビューがタッチを取得しているように見えますが、それらは下のビューに渡されません。
[〜#〜] update [〜#〜]
これは、レスポンダーチェーンの動作方法によるものですか?私のビュー階層は次のようになります。
VC - View1
-View2
-imageView1 (has tapGestureRecogniser)
-imageView2
-View3
-button1
-button2
OSは最初にView2が前面にあるとヒットテストを行うため、すべてのタッチを取得する必要があり、View2のuserInteractionsがNOに設定されていない限り、これらはView3に渡されません。その場合、imageView1もタッチを受信できなくなります。これはどのように機能しますか?また、View2がView3へのタッチを通過する方法はありますか?
UIGestureRecognizerは私が思うにニシンです。これを解決するために、最後にpointInside:withEvent:
私のメソッドUIView:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL pointInside = NO;
if (CGRectContainsPoint(imageView.frame, point) || expanded) pointInside = YES;
return pointInside;
}
これにより、imageViewをタッチするか、その展開フラグが設定されている場合、ビューはすべてのタッチをトラップします。展開されていない場合、タッチがimageView上にある場合にのみタッチをトラップします。
NOを返すことにより、トップレベルVCのビューは、ヒットを探してビュー階層の残りの部分を照会します。
View
またはStoryboard
でXIB
を選択して...
またはSwiftの場合
view.isUserInteractionEnabled = false
IGestureRecognizerDelegate Protocol を調べます。具体的には、gestureRecognizer:shouldReceiveTouch:
各UIGestureRecognizer
をUIViewController
のプロパティにする必要があります。
// .h
@property (nonatomic, strong) UITapGestureRecognizer *lowerTap;
// .m
@synthesize lowerTap;
// When you are adding the gesture recognizer to the image view
self.lowerTap = tapGestureRecognizer
UIViewController
をデリゲートにしてください。
[self.lowerTap setDelegate: self];
そして、あなたはこのようなものを持っているでしょう、
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (expanded && gestureRecognizer == self.lowerTap) {
return NO;
}
else {
return YES;
}
}
もちろん、これは正確なコードではありません。しかし、これは一般的なパターンです。
@Magic Bullet Daveのソリューションですが、Swiftで
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
var pointInside = false
if commentTextField.frame.contains(point) {
pointInside = true
} else {
commentTextField.resignFirstResponder()
}
return pointInside
}
ImagePickerViewController.cameraOverlayのCameraOverlayViewで使用して、ユーザーが新しい写真を撮影しながらコメントできるようにします
別の解決策があります。私には2つのビューがあり、それらをオーバーラップしていたCustomSubView
と呼びましょう。両方ともタッチを受け取るはずです。そこで、View ControllerとカスタムUIViewクラスを用意し、インターフェイスビルダーで設定したViewControllerView
と呼んで、そのビューへのタッチを受け取る2つのビューを追加しました。
そこで、hitTestを上書きしてViewControllerView
のタッチをインターセプトしました。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return self;
}
それからViewControllerView
で上書きしました:
- (void)touchesBegan:(NSSet *)touches
withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
for (UIView *subview in [self.subviews reverseObjectEnumerator])
{
if ([subview isKindOfClass:[CustomSubView class]])
{
[subview touchesBegan:touches withEvent:event];
}
}
}
touchesMoved
touchesEnded
およびtouchesCancelled
でもまったく同じことを行います。
// this is due to userInteractionEnabled deficiency: the flag stops traversal of subviews
@objc(YourObjcPrefixHereForXibAndStoryboardUseViewTransparentToTouch)
open class ViewTransparentToTouch: UIView
{
public var daisyView: UIView?
override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let hitView = super.hitTest(point, with: event)
if hitView === self {
return daisyView
}
return hitView // childView
}
}